我有一个简单的日期选择器组件,带有用于预设日期范围的按钮。

reactjs - 在不使用use的情况下传达组件的初始状态-LMLPHP

问题出在我的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 }));
};

09-25 19:01