传递给其他功能组件的回调是否在刷新时更新?
Are callbacks that are passed into other functional components updated on refresh?
我有一个复杂的表单,其中包含不同类型的输入元素。为简单起见,我将其限制为一个,因为每个有效地遵循相同的方法。
const Form = () => {
const [state, setState] = useState();
const handleChange = useCallback((name, value) => {
setState({
...state,
[name]: value
})
}, [state, setState]);
useEffect(() => {
console.log(state)
}, [state, setState]);
return (
<div>
<Input name="inputOne" onChange={handleChange} />
<Input name="inputTwo" onChange={handleChange} />
</div>
);
}
const Input = ({ name, onChange }) => {
const [value, setValue] = useState("");
const handleChange = useCallback((e) => {
setValue(e.target.value);
onChange(name, e.target.value)
}, [value, setValue]);
return (
<input onChange={handleChange} value={value}/>
);
}
出于某种原因,在使用此表单时。如果我在第一个输入中输入值,我得到的结果记录为
{ "inputOne": "value entered into input one" }
但是如果我在第二个输入中输入一些东西,我会得到这个
{ "inputTwo": "value entered into input two" }
如果我返回并再次输入 inputOne
,我们会再次得到这个。
{ "inputOne": "value entered into input one, and more text entered" }
据我所知,我编写的代码应该在状态更改时更新回调,以便传播的新状态 (...state) 是最新的状态值。然后在我将 handleChange
函数传递到的所有元素中更新它。但是,似乎 handleChange
在传递到 onChange
参数的地方没有更新,因此调用旧回调时状态 属性 被错误保存。
谁能告诉我这是否正确以及 handleChange
回调没有正确更新?就像两个 Input 都看到了对 handleChange
回调的不同引用。
你的问题是一个非常典型的闭包问题。
旧参考资料的获取方式非常复杂,但让我尽量解释一下
当您创建表单组件时,您的 handleChange 函数会在每次状态更改时更新,并传递给 Input 组件。然而,即使更新的实例传递给 child,child 也不会使用更新的实例,除非它自己的值发生变化。现在,当它尝试更新其值时,它正在调用旧的引用函数,该函数中没有反映其他输入值。
有两种方法可以解决这个问题
- 使用回调方法来设置状态,这样无论闭包中的值如何,您都可以通过 React 获得最新状态
- 解决它的另一种方法是在 Input 组件中添加 onChange 作为对 useCallback 的依赖,这样即使其他输入元素导致状态更改,所有 Input 都有 onChange 函数的最新引用
const { useCallback, useState, useEffect } = React;
const Form = () => {
const [state, setState] = useState({});
const handleChange = useCallback((name, value) => {
setState(prev=> ({
...prev,
[name]: value
}))
}, [setState]);
useEffect(() => {
console.log(state);
}, [state, setState]);
return (
<div>
<Input name="inputOne" onChange={handleChange} />
<Input name="inputTwo" onChange={handleChange} />
</div>
);
}
const Input = ({ name, onChange }) => {
const [value, setValue] = useState("");
const handleChange = useCallback((e) => {
setValue(e.target.value);
onChange(name, e.target.value)
}, [value, setValue]);
return (
<input onChange={handleChange} value={value}/>
);
}
ReactDOM.render(<Form />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />
P.S. 如果您正在使用 useCallback
并将状态添加为依赖项并且您在自身内部更新状态,则它不会实现任何目标每次更新都会创建一个单独的实例。
最好使用 setState
的函数式方法来解决这个问题并更好地记忆
我有一个复杂的表单,其中包含不同类型的输入元素。为简单起见,我将其限制为一个,因为每个有效地遵循相同的方法。
const Form = () => {
const [state, setState] = useState();
const handleChange = useCallback((name, value) => {
setState({
...state,
[name]: value
})
}, [state, setState]);
useEffect(() => {
console.log(state)
}, [state, setState]);
return (
<div>
<Input name="inputOne" onChange={handleChange} />
<Input name="inputTwo" onChange={handleChange} />
</div>
);
}
const Input = ({ name, onChange }) => {
const [value, setValue] = useState("");
const handleChange = useCallback((e) => {
setValue(e.target.value);
onChange(name, e.target.value)
}, [value, setValue]);
return (
<input onChange={handleChange} value={value}/>
);
}
出于某种原因,在使用此表单时。如果我在第一个输入中输入值,我得到的结果记录为
{ "inputOne": "value entered into input one" }
但是如果我在第二个输入中输入一些东西,我会得到这个
{ "inputTwo": "value entered into input two" }
如果我返回并再次输入 inputOne
,我们会再次得到这个。
{ "inputOne": "value entered into input one, and more text entered" }
据我所知,我编写的代码应该在状态更改时更新回调,以便传播的新状态 (...state) 是最新的状态值。然后在我将 handleChange
函数传递到的所有元素中更新它。但是,似乎 handleChange
在传递到 onChange
参数的地方没有更新,因此调用旧回调时状态 属性 被错误保存。
谁能告诉我这是否正确以及 handleChange
回调没有正确更新?就像两个 Input 都看到了对 handleChange
回调的不同引用。
你的问题是一个非常典型的闭包问题。
旧参考资料的获取方式非常复杂,但让我尽量解释一下
当您创建表单组件时,您的 handleChange 函数会在每次状态更改时更新,并传递给 Input 组件。然而,即使更新的实例传递给 child,child 也不会使用更新的实例,除非它自己的值发生变化。现在,当它尝试更新其值时,它正在调用旧的引用函数,该函数中没有反映其他输入值。
有两种方法可以解决这个问题
- 使用回调方法来设置状态,这样无论闭包中的值如何,您都可以通过 React 获得最新状态
- 解决它的另一种方法是在 Input 组件中添加 onChange 作为对 useCallback 的依赖,这样即使其他输入元素导致状态更改,所有 Input 都有 onChange 函数的最新引用
const { useCallback, useState, useEffect } = React;
const Form = () => {
const [state, setState] = useState({});
const handleChange = useCallback((name, value) => {
setState(prev=> ({
...prev,
[name]: value
}))
}, [setState]);
useEffect(() => {
console.log(state);
}, [state, setState]);
return (
<div>
<Input name="inputOne" onChange={handleChange} />
<Input name="inputTwo" onChange={handleChange} />
</div>
);
}
const Input = ({ name, onChange }) => {
const [value, setValue] = useState("");
const handleChange = useCallback((e) => {
setValue(e.target.value);
onChange(name, e.target.value)
}, [value, setValue]);
return (
<input onChange={handleChange} value={value}/>
);
}
ReactDOM.render(<Form />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />
P.S. 如果您正在使用 useCallback
并将状态添加为依赖项并且您在自身内部更新状态,则它不会实现任何目标每次更新都会创建一个单独的实例。
最好使用 setState
的函数式方法来解决这个问题并更好地记忆