我有一个简单的日期选择器组件,带有用于预设日期范围的按钮。
问题出在我的useEffect
中:我正在使用它来传达渲染上的初始状态,但是React当然会发出警告(“ useEffect缺少依赖项”)。
有一个好的模式可以做到这一点吗?
孩子:
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>
答案 0 :(得分:3)
eslint警告,警告用户有关useEffect的不当使用。由于钩子在很大程度上取决于闭包,因此正确编写钩子非常重要
现在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 }));
};
现在最后一件事,如果在onUpdate的父级中使用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} />
)
}
孩子
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 }));
};