如何使用钩子使用数据对象更新React状态

时间:2020-02-14 17:40:42

标签: javascript reactjs react-hooks

我有一个带有日期选择器的组件,并且想使用钩子在状态下更改日期选择器的值,以及日期选择器本身中的日期,因此您可以选择一个日期,或者可以单击一个按钮以设置一个日期,例如30天前。

这是我到目前为止尝试过的:

const MyComp = () => {

  const [formData, setFormData] = useState({
    dateFrom: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
    dateTo: new Date()
  });

  const handleDateClick = interval => {
    setFormData({...formData, dateFrom: new Date(Date.now() - interval * 24 * 60 * 60 * 1000)});
    setFormData({...formData, dateTo: new Date()});
  };

  const handleOnChange = e => {
    setFormData({...formData, [e.target.name]: e.target.value});
  };

  return (
    <Button onClick={() => handleDateClick(30)} variant="secondary">30 days ago</Button>

    <DatePicker
      selected={formData.dateFrom}
      name="dateFrom"
      dateFormat="MMMM d, yyyy"
      onChange={value => handleOnChange({target: {name: "dateFrom", value}})}
    />
);

}

单击按钮无效,甚至不显示任何错误,状态没有更新,并且日期选择器中的值没有更改?有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您看到奇怪行为的原因是因为您的handleDateClick连续调用了两次setFormData,这是一个问题,因为setFormData是异步的,这意味着不会立即反映和更新您的状态。

有关更多详细信息,请参见此SO问题:

因此,实际上最终发生的事情是,您更新了dateFrom,但之后立即再次调用setFormData,并且由于它使用了旧状态,因此您从未见过dateFrom的更新值。

const handleDateClick = interval => {
  setFormData({ ...formData, dateFrom: ... })

  // uses the value of `dateFrom` from the "old state"
  // when you do `...formData`, then updates `dateTo`
  setFormData({ ...formData, dateTo: ... })
}

我建议您将handleDateClick中的所有更新合并到一个setFormData调用中。从外观上看,您没有理由打两个单独的电话。

这是您应该如何处理的方法:

function Button({ children, ...rest }) {
  return <button {...rest}>{children}</button>;
}

function MyComp() {
  const [formData, setFormData] = React.useState({
    dateFrom: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
    dateTo: new Date()
  });

  const handleDateClick = interval => {
    setFormData({
      dateTo: new Date(),
      dateFrom: new Date(Date.now() - interval * 24 * 60 * 60 * 1000)
    });
  };

  return (
    <>
      <Button onClick={() => handleDateClick(30)}>Click me!</Button>
      <p>
        <b>State:</b> {JSON.stringify(formData)}
      </p>
    </>
  );
}

如果您想看看,这是一个工作示例: