在useState的函数中丢失用于更新状态的综合事件

时间:2020-03-08 05:42:53

标签: javascript reactjs

我正在将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()来实现。 我的问题是,为什么它在我解释的第一种情况下起作用,为什么在第二种情况下不起作用?

4 个答案:

答案 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()来防止的。