【问题标题】:UseEffect and useCallback still causes infinite loop in react projectUseEffect 和 useCallback 仍然会导致 React 项目中的无限循环
【发布时间】:2020-07-18 05:32:45
【问题描述】:

我似乎无法解决我的 react 项目中的无限循环问题。

我正在开发一个每日日志反应应用程序。让我简要解释一下这个项目。下面是代码图片供快速查看:

底部有相同的代码。

结构(从上到下)

  1. DailyLog 组件有一个使用 Question 组件的表单,其中传递了 props。
  2. Question 组件使用道具来显示问题和描述。它还包含一个 Input 组件,props 会进一步向下传递。
  3. Input 组件获取道具并呈现适当的表单输入字段。

逻辑(从下到上)

  1. Input 组件处理它自己的inputState。当用户输入内容并触发onChangeHandler 时,状态会发生变化。
  2. Input 组件还有一个useEffect() 钩子,它调用一个onInput() 函数,该函数作为道具从DailyLog 传递下来。
  3. DailyLog 组件中的onInputHandler() 更新formState,这是包含所有输入字段值的表单范围状态。 formState 会根据当时填写的输入字段进行修改。
  4. onInputHandler() 使用useCallback() 钩子,它应该停止由任何父/子重新渲染引起的无限循环。但它不起作用:皱眉:

代码有什么问题?我在这里想念什么?代码如下:

//DailyLog.js
import React, { useState, useCallback } from 'react';

import Question from '../components/FormElements/Question';
import questionData from '../components/DailyLog/questionData';
import './DailyLog.css';

const DailyLog = () => {
    const [formState, setFormState] = useState();

    const onInputHandler = useCallback(
        (inputId, inputValue) => {
            setFormState({
                ...formState,
                [inputId]: inputValue,
            });
        },
        [formState]
    );

    return (
        <main className="container">
            <form action="" className="form">
                <Question
                    id="title"
                    element="input"
                    type="text"
                    placeholder="Day, date, calendar scheme"
                    onInput={onInputHandler}
                />

                <Question
                    id="focus"
                    question={questionData.focusQuestion}
                    description={questionData.focusDescription}
                    element="textarea"
                    placeholder="This month's focus is... This week's focus is..."
                    onInput={onInputHandler}
                />
            </form>
        </main>
    );
};

export default DailyLog;

//Question.js
import React from 'react';

import Input from './Input';
import './Question.css';

const Question = props => {
    return (
        <div className="form__group">
            {props.question && (
                <label className="form__label">
                    <h2>{props.question}</h2>
                </label>
            )}

            <small className="form__description">{props.description}</small>

            <Input
                id={props.id}
                element={props.element}
                type={props.type}
                placeholder={props.placeholder}
                onInput={props.onInput}
            />
        </div>
    );
};

export default Question;

//Input.js
import React, { useState, useEffect } from 'react';

import './Input.css';

const Input = props => {
    const [inputState, setInputState] = useState();

    const { id, onInput } = props;

    useEffect(() => {
        onInput(id, inputState);
    }, [id, onInput, inputState]);

    const onChangeHandler = event => {
        setInputState(event.target.value);
    };

    // check if question element type is for input or textarea
    const element =
        props.element === 'input' ? (
            <input
                id={props.id}
                className="form__field"
                type={props.type}
                value={inputState}
                placeholder={props.placeholder}
                onChange={onChangeHandler}
            />
        ) : (
            <textarea
                id={props.id}
                className="form__field"
                rows="1"
                value={inputState}
                placeholder={props.placeholder}
                onChange={onChangeHandler}
            />
        );

    return <>{element}</>;
};

export default Input;

【问题讨论】:

  • 分享您的代码而不是图片!
  • 现在添加代码。提供图片是因为我认为并排阅读和理解组件会更容易。

标签: reactjs infinite-loop use-effect usecallback


【解决方案1】:

从 useEffect 敏感列表中移除 id 和 onInput

useEffect(() => {
        onInput(id, inputState);
}, [inputState]);

并将 inputState 的默认值设置为 '' 如下:

const [inputState, setInputState] = useState('');

为了防止“一个组件正在将一个不受控制的文本类型的输入更改为 ReactJS 中的受控错误”。你也可以初始化formState:

const [formState, setFormState] = useState({title:'', focus:''});

【讨论】:

  • 谢谢!这解决了问题,但现在我得到另一个错误。警告:组件正在更改要控制的文本类型的不受控输入。输入元素不应从不受控切换到受控(反之亦然)。在组件的生命周期内决定使用受控或不受控的输入元素
  • 现在也在useCallback()中,如果我console.log(formState),会有1步延迟。如果我在输入字段中输入任何内容,例如 1 然后 2 然后 3。控制台首先记录未定义,然后 1 然后 2。
  • 很简单 init const [formState, setFormState] = useState({title:'', focus:''});
  • 非常感谢您的帮助!我真的很感谢你抽出时间。 formState 虽然延迟了 1 步。建议?
  • setFormState 是异步的,因此当您记录 formState 时,您实际上记录了以前的 formState,记录 inputValue,您会发现它没有延迟 1 步!
猜你喜欢
  • 2021-01-14
  • 1970-01-01
  • 2022-06-17
  • 2021-11-01
  • 2021-02-19
  • 2021-06-06
  • 2020-08-27
  • 2020-11-16
相关资源
最近更新 更多