我正在将useState挂钩用于功能组件,这些功能组件我面临一种奇怪的行为。 我正在这样使用useState。
const [state, setState] = useState({ title: "", amount: '' });
相同状态,我正在绑定表单数据。如果我以前喜欢这样
<input type="text" id="title" value={state.title}
onChange={event => setState( { ...state, title: event.target.value })} />
那么它就完美地工作了,但是如果我使用前一个State作为这样的实时状态
<input type="text" id="title" value={state.title}
onChange={event => setState((prevState) => {
return {
...prevState,
title: event.target.value
}
})
} />
然后事件会在第二次按键时松开。在研究中,我发现这是由于事件池引起的,我可以使用event.persist()来实现。 我的问题是,为什么它在我解释的第一种情况下起作用,为什么在第二种情况下不起作用?
答案 0 :(得分:1)
实际上发生的事情是由于关闭和React处理事件的方式。 setState下的function是闭包函数,因此event的值在首次执行时被锁定,闭包尝试获取第一个值(锁定值)。 React实现Event pooling,其中在事件回调被调用后,事件对象将被无效。
但是,React还提供了一种方法,可以使用如下的persist方法从事件池中提取 event 对象。
`onChange={event => {
event.persist();
setState(prevSt....`
通过这种方式,React将永远不会使对象无效,因此闭包将始终可以访问事件方法。
答案 1 :(得分:0)
由于在第二次迭代中,Event参数变得未定义。因此它找不到引发null异常的值。您可以通过传递箭头功能来克服这种情况
// Get a hook function
const {useState} = React;
const Example = ({title}) => {
const [count, setCount] = useState(0);
const [state, setState] = useState({ title: "", amount: '' });
const setValue = (value) => {
setState((prevState) => {
console.log(prevState);
return {
...prevState,
title: value//(event.target?event.target.value : 'val')
}
})
}
return (
<div>
<input type="text" id="title" value={state.title}
onChange={event => setState({ ...state, title: event.target.value })} />
<input type="text" id="title" value={state.title}
onChange={event => setValue(event.target.value)}
/>
</div>
);
};
// Render it
ReactDOM.render(
<Example title="Example using Hooks:" />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
答案 2 :(得分:0)
因此,在setState( { ...state, title: event.target.value })
中,您将分散状态,这意味着维持当前状态并将状态对象的title
更改为input
中的当前值。在
setState((prevState) => {
return {
...prevState,
title: event.target.value
}
})
使用事件池,因此prevState
是作为回调发送的事件数据(在本例中为状态对象),因此当您输入第一个字符时,事件对象实际上就被发送回了池中,并且当您输入第二个字符时,事件对象将已经返回到池中,因此事件将为null
。因此,要克服此问题,您可以使用event.persist()
使事件持久化,该方法将允许您以异步方式使用事件属性,希望这会有所帮助
<input
type='text'
id='title'
value={state.title}
onChange={event => {
event.persist();
setState(prevState => {
return {
...prevState,
title: event.target.value
};
});
}}
/>
答案 3 :(得分:0)
在第一个示例中,您直接在事件处理程序中读取事件数据,而事件仍然是 current 。但是,在第二个示例中,您正在传递给setState()
的回调中读取它。当状态已更新(即其全部内容)时,该回调将被异步调用,此时事件处理程序已经返回并且本机事件(由React的SyntheticEvent包装)已被取消引用。这是通过调用event.persist()
来防止的。