我有一个简单的日期选择器组件,带有用于预设日期范围的按钮。
问题出在我的useEffect
中:我正在使用它来传递渲染上的初始状态,但是React当然会发出警告(“useEffect缺少依赖项”)。
有一个好的模式可以做到这一点吗?
child :
const LAST_7 = "LAST_7";
let to, from, filter;
// figure out values for "from", "to", and "filter" (which is set to LAST_7 in case "from" and "to" are not in props)
const initial = {
from,
to,
filter,
};
const [state, setState] = useState(initial);
useEffect(() => {
props.onUpdate(from, to);
}, []);
const handleClick = (e) => {
const filter = e.target.value;
const { from, to } = getDatesFromFilterValue(filter);
setState((prev) => ({ ...prev, from, to, filter }));
props.onUpdate(from, to);
};
上级:
const onDatesUpdate = (from, to) => {
setState((prev) => ({ ...prev, from, to }));
};
// ...
<Child
onUpdate={onDatesUpdate}
></Child>
最佳答案
此处有eslint警告,警告用户有关useEffect的不当使用。由于钩子(Hook)在很大程度上取决于闭包,因此非常重要的一点是我们正确编写它们
现在eslint警告您缺少依赖项的原因是因为您在useEffect中使用了onUpdate
现在,ESlint并不是不是很聪明,就可以算出您作为开发人员想要的东西
希望只在初始渲染时才调用该函数绝对是可以的。但是,ESlint不知道函数中是否有依赖于关闭变量的间隔或订阅,因此警告您,只要重新创建onUpdate或更改其依赖项,就可能需要重新运行onUpdate。
如果您完全确定所写内容正确无误,则可以禁用警告,例如
useEffect(() => {
props.onUpdate(from, to);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
既然您打算从on调用onUpdate并通过handleClick进行更改,那么实际上也可以将它们添加为依赖项
const [state, setState] = useState(initial);
useEffect(() => {
props.onUpdate(from, to);
}, [from, to]);
const handleClick = (e) => {
const filter = e.target.value;
const { from, to } = getDatesFromFilterValue(filter);
setState((prev) => ({ ...prev, from, to, filter }));
};
现在最后一件事,如果在其父项中使用useCallback编写onUpdate以确保仅在需要时创建onUpdate,则可以将onUpdate添加为对useEffect的依赖项
const Parent = () => {
const [state, setState]= useState({});
const onUpdate = useCallback((from, to) => {
setState(prev => ({
// use functional setState here to get updated state using prev
// and return the updated value
}))
}, [])
...
return (
<Child onUpdate={onUpdate} />
)
}
child
const [state, setState] = useState(initial);
useEffect(() => {
props.onUpdate(from, to);
}, [from, to, onUpdate]);
// Now that onUpdate is created on once, adding it to dependency will not be an issue
const handleClick = (e) => {
const filter = e.target.value;
const { from, to } = getDatesFromFilterValue(filter);
setState((prev) => ({ ...prev, from, to, filter }));
};