react HTML 选择元素 onChange 函数,尝试访问“event.target.value”

IT技术 javascript html reactjs react-hooks
2021-05-07 05:19:59

<select>在 React 中使用受控 HTML标签时。

关于下面的片段:

为什么这样做:

选项1

function changeSelect(event) {
  const newValue = event.target.value;
  setNestedState((prevState) => {
    return({
      ...prevState,
      propA: newValue
    });
  });
}

而这不是?(它仅适用于第一次更改)

选项#2

function changeSelect(event) {
  setNestedState((prevState) => {
    return({
      ...prevState,
      propA: event.target.value
    });
  });
}

片段(使用选项 #2)

function App() {
  
  const [nestedState,setNestedState] = React.useState({
    propA: 'foo1',
    propB: 'bar'
  });
  
  function changeSelect(event) {
    // const newValue = event.target.value;
    setNestedState((prevState) => {
      return({
        ...prevState,
        propA: event.target.value    // THIS DOES NOT WORK
      });
    });
  }
  
  return(
    <React.Fragment>
      <div>My nested state:</div>
      <div>{JSON.stringify(nestedState)}</div>
      <select 
        value={nestedState.propA} 
        onChange={changeSelect}
      >
        <option value='foo1'>foo1</option>
        <option value='foo2'>foo2</option>
        <option value='foo3'>foo3</option>
      </select>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<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="root"/>

2个回答

这里event(onChange) 是一个synthetic event. React重用synthetic events,这意味着当函数执行完成时,它event会使event pool.

由于setStateisasync并且eventonChange被调用后被取消,直接访问event.target.value异步回调中的事件属性(即)将不起作用。

一种方法是将 a 中的值存储synthetic event到一个变量中,例如:

function changeSelect(event) {
  const newValue = event.target.value; // reference
  setNestedState((prevState) => {
    return({
      ...prevState,
      propA: newValue // can use event properties
    });
  });
}

使其异步工作的另一种方法是使用event.persist().

文档中

如果要以异步方式访问事件属性,则应调用event.persist()该事件,这将从池中删除合成事件并允许用户代码保留对该事件的引用。

function changeSelect(event) {

  event.persist();   //This will persist the event

  setNestedState((prevState) => {
    return({
      ...prevState,
      propA: event.target.value
    });
  });
}

演示

与 ravibagul91 一样正确,我认为您正在采取一种复杂的路线来做一件相对简单的事情,而您并没有真正利用 state 的实际运作方式。

首先,您是否从 propB 与 propA 处于同一状态对象中得到了什么?从代码上看,似乎不是这样,在不同的状态下管理 propA 和 propB 也不是一个坏主意。

也就是说,您可以直接从选择中调用某个状态的 set 方法,因为它看起来好像您不需要了解有关前一个状态的任何信息。

function App() {

  const [propA,setPropA] = React.useState('');
  const [propB,setPropB] = React.useState('');

  return(
    <React.Fragment>
      <div>Prop A: {propA}</div>
      <div>Prop B: {propB}</div>
      <select 
        value={propA} 
        onChange={e => setPropA(e.target.value)}
      >
        <option value='foo1'>foo1</option>
        <option value='foo2'>foo2</option>
        <option value='foo3'>foo3</option>
      </select>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));

更容易阅读、理解和维护 IMO。