简体   繁体   English

setState 仅在使用 object 作为 state 时设置最后一个输入

[英]setState only setting last input when using object as state

Im trying to create a form with React.我试图用 React 创建一个表单。 This form uses a custom Input component I created various times.此表单使用我多次创建的自定义输入组件。 In the parent form Im trying to get a complete object with all names and all values of the form:在父表单中,我试图获得一个完整的 object ,其中包含表单的所有名称和所有值:

  {inputName: value, inputName2: value2, inputName3: value3}

For this, I created a 'component updated' hook, that calls the function property onNewValue to send the new value to the parent (two way data binding):为此,我创建了一个“组件更新”挂钩,它调用 function 属性onNewValue将新值发送到父级(双向数据绑定):

  useEffect(() => {
    if (onNewValue) onNewValue({ name, value });
  }, [value]);

The parent form receives the data in the handleInputChange function:父窗体接收handleInputChange function中的数据:

export default () => {
  const [values, setValues] = useState({});

  const handleInputChange = ({
    name,
    value
  }: {
    name: string;
    value: string | number;
  }): void => {
    console.log("handleInputChange", { name, value }); // All elements are logged here successfully
    setValues({ ...values, [name]: value });
  };

  return (
    <>
      <form>
        <Input
          name={"nombre"}
          required={true}
          label={"Nombre"}
          maxLength={30}
          onNewValue={handleInputChange}
        />
        <Input
          name={"apellidos"}
          required={true}
          label={"Apellidos"}
          maxLength={60}
          onNewValue={handleInputChange}
        />
        <Input
          name={"telefono"}
          required={true}
          label={"Teléfono"}
          maxLength={15}
          onNewValue={handleInputChange}
        />
        <Input
          name={"codigoPostal"}
          required={true}
          label={"Código Postal"}
          maxLength={5}
          onNewValue={handleInputChange}
          type={"number"}
        />
      </form>
      State of values: {JSON.stringify(values)}
    </>
  );
};

This way all elements from all inputs should be set on init :这样,所有输入的所有元素都应该在 init上设置:

  {"codigoPostal":"","telefono":"","apellidos":"","nombre":""}

But for some reason only the last one is being set:但由于某种原因,只设置了最后一个

  {"codigoPostal":""}

You can find the bug here: https://codesandbox.io/s/react-typescript-vx5py你可以在这里找到错误: https://codesandbox.io/s/react-typescript-vx5py

Thanks!谢谢!

useState() doesn't merge the states unlike this.setState() in a class.与 class 中的 this.setState() 不同, this.setState()不会合并状态。

So better off separate the fields into individual states.所以最好将这些字段分成单独的状态。

const [nombre, setNombre] = useState("")
const [apellidos, setApellidos] = useState("")
// and so on

UPDATE :更新

Given setValue() is async use previous state during init.给定setValue()是异步的,在初始化期间使用之前的 state。

setValues((prevState) => ({ ...prevState, [name]: value }));

The set state process in React is an asynchronous process. React中设置的state进程是一个异步进程。 Therefore even if the function is called, values has not updated the previous state just yet.因此,即使调用了 function, values还没有更新之前的 state。

To fix, this you can use the functional version of setState which returns the previous state as it's first argument.要解决此问题,您可以使用setState的功能版本,它返回以前的 state 作为它的第一个参数。

setValues(values=>({ ...values, [name]: value }));

The updated and fixed code, look at:更新和修复的代码,请看:

https://codesandbox.io/s/react-typescript-mm7by https://codesandbox.io/s/react-typescript-mm7by

look at:看着:

  const handleInputChange = ({
    name,
    value
  }: {
    name: string;
    value: string | number;
  }): void => {
    console.log("handleInputChange", { name, value });
    setValues(prevState => ({ ...prevState, [name]: value }));
  };
 const [ list, setList ] = useState( [ ] );

correct:正确的:

 setList ( ( list ) => [ ...list, value ] )

avoid use:避免使用:

 setList( [ ...list, value ] )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM