React hook useEffect 依赖数组

React hook useEffect dependency array

我正在努力思考 React 的新钩子 api。具体来说,我正在尝试构建曾经是以下的经典用例:

componentDidUpdate(prevProps) {
    if (prevProps.foo !== this.props.foo) {
        // animate dom elements here...
        this.animateSomething(this.ref, this.props.onAnimationComplete);
    }
}

现在,我尝试使用函数组件和 useEffect 构建相同的组件,但不知道该怎么做。这是我试过的:

useEffect(() => {
    animateSomething(ref, props.onAnimationComplete);
}, [props.foo]);

这样,效果只在props.foo变化时调用。这确实有效——但是!它似乎是一种反模式,因为 eslint-plugin-react-hooks 将其标记为错误。效果中使用的所有依赖项都应在 dependencies 数组中声明。所以这意味着我必须执行以下操作:

useEffect(() => {
    animateSomething(ref, props.onAnimationComplete);
}, [props.foo, ref, props.onAnimationComplete]);

这不会导致 linting 错误,但它完全违背了 props.foo 更改时调用效果的目的。我不想在其他道具或裁判发生变化时调用它。

现在,我阅读了一些关于使用 useCallback 来包装它的内容。我试过了,但没有进一步。

有人可以帮忙吗?

我建议这样写:

const previousFooRef = useRef(props.foo);

useEffect(() => {
    if (previousFooRef.current !== props.foo) {
       animateSomething(ref, props.onAnimationComplete);
       previousFooRef.current = props.foo;
    }
}, [props.foo, props.onAnimationComplete]);

您无法避免在效果中设置条件的复杂性,因为如果没有它,您将 运行 动画挂载,而不是仅在 props.foo 更改时。该条件还允许您避免在 props.foo 以外的事情发生变化时进行动画处理。

通过在 dependencies 数组中包含 props.onAnimationComplete,您可以避免禁用 lint 规则,这有助于确保您不会引入与缺少依赖项相关的未来错误。

这是一个工作示例:

抑制 linter,因为它给了你一个糟糕的建议。 React 要求您将值传递给第二个参数,这些值(并且只有哪些)更改必须触发效果。

useEffect(() => {
    animateSomething(ref, props.onAnimationComplete);
}, [props.foo]); // eslint-disable-line react-hooks/exhaustive-deps

它导致与 相同的结果。

我认为违反此 linter 规则没有问题。与 useCallbackuseMemo 相比,它在一般情况下不会导致错误。第二个参数的内容是高层逻辑。

您甚至可能希望在无关值更改时调用效果:

useEffect(() => {
    alert(`Hi ${props.name}, your score is changed`);
}, [props.score]);

将回调中的值移动到 refs:

const elementRef = useRef(); // Ex `ref` from the question
const animationCompleteRef = useRef();

animationCompleteRef.current = props.onAnimationComplete;

useEffect(() => {
    animateSomething(elementRef, animationCompleteRef.current);
}, [props.foo, elementRef, animationCompleteRef]);

之所以有效,是因为 useRef return 值在渲染时不会改变。