我有一个带有日期选择器的组件,并且想使用钩子更改状态中日期选择器的值,以及日期选择器本身中的日期,因此您可以选择日期,也可以单击按钮设置日期,例如 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}})}
/>
);
}
单击按钮不起作用,甚至不显示任何错误,状态未更新,日期选择器中的值未更改?请问有什么想法吗?
您看到奇怪行为的原因是您的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>
</>
);
}
如果您想查看,这里有一个工作示例:
- 代码沙盒