我有一个带有日期选择器的组件,并且想使用钩子在状态下更改日期选择器的值,以及日期选择器本身中的日期,因此您可以选择一个日期,或者可以单击一个按钮以设置一个日期,例如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}})}
/>
);
}
单击按钮无效,甚至不显示任何错误,状态没有更新,并且日期选择器中的值没有更改?有什么想法吗?
答案 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>
</>
);
}
如果您想看看,这是一个工作示例: