反应钩子详尽的暗示建议无限循环

时间:2020-10-12 11:09:54

标签: reactjs react-native react-hooks expo

我收到以下esLint错误

React Hook useEffect has a missing dependency: 'time'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps) (ESLint)

如果我遵循建议,并提供time作为依赖项数组的一部分,我将得到一个无限循环,因为setTime道具将不断更新time道具。

const TimeValidator = ({
    time,
    setTime
}: {
    time: Time;
    setTime: (time: Time) => void;
}) => {
    const [newTime, setNewTime] = useState(time);

    useEffect(() => {
        // Save the duration from the time property
        const duration = time.end - time.start;
        if (newTime.start > time.end) {
            // Use the duration to create a valid time object, where "start" < "end"
            setTime({ start: newTime.start, end: newTime.start + duration });
        } else if (newTime.end < time.start) {
            // Use the duration to create a valid time object, where "start" < "end"
            setTime({ start: newTime.end, end: newTime.end + duration });
        } else {
            setTime({ ...time, ...newTime });
        }
        // react-hooks/exhaustive-deps suggests "time". But this will lead to
        // infinite update loop
    }, [newTime, setTime]);

    return <TimeChooser time={time} setTime={setNewTime} />;
};

Link to expo snack - Try to update the time in dependency array

这个想法是父级传递一个time对象和一个回调来更新时间对象。 TimeValidatortime对象向下传递给子对象TimeChoser,但覆盖了回调。如果从time的子代更新的TimeValidator无效,则TimeValidator将尝试更新time对象,因此start总是小于end

是否有解决此问题的好方法?谢谢!

2 个答案:

答案 0 :(得分:1)

有时es-lint在真正的用例中会有一些例外。在这种情况下,您必须使用// eslint-disable-next-line注释。

useEffect(() => {
 ----
 // eslint-disable-next-line
},[newTime, setTime])

答案 1 :(得分:0)

我认为我可以将useEffect转换为useCallback:

const TimeValidator = ({
    time,
    setTime
}: {
    time: Time;
    setTime: (time: Time) => void;
}) => {
    const updatedTracking = useCallback(
        (newTime, updateTime) => {
            // Save the duration from the time property
            const duration = time.end - time.start;
            if (newTime.start > time.end) {
                // Use the duration to create a valid time object, where "start" < "end"
                updateTime({
                    start: newTime.start,
                    end: newTime.start + duration
                });
            } else if (newTime.end < time.start) {
                // Use the duration to create a valid time object, where "start" < "end"
                updateTime({ start: newTime.end, end: newTime.end + duration });
            } else {
                updateTime({ ...time, ...newTime });
            }
        },
        [time]
    );

    return (
        <TimeChooser
            time={time}
            setTime={time => updatedTracking(time, setTime)}
        />
    );
};