使用 useEffect,如何跳过在初始渲染时应用效果?

新手上路,请多包涵

使用 React 的新效果挂钩,如果某些值在重新渲染之间没有更改,我可以告诉 React 跳过应用效果 - React 文档中的示例:

 useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

但是上面的示例将效果应用于初始渲染以及后续重新渲染时 count 已更改。我如何告诉 React 跳过初始渲染的效果?

原文由 uturnr 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 906
2 个回答

正如指南所述,

Effect Hook,useEffect,增加了从函数组件执行副作用的能力。它的用途与 React 类中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 相同,但统一到一个 API 中。

在本指南的示例中,预计 count 仅在初始渲染时为 0:

 const [count, setCount] = useState(0);

所以它将作为 componentDidUpdate 工作,并进行额外检查:

 useEffect(() => {
  if (count)
    document.title = `You clicked ${count} times`;
}, [count]);

这基本上是可以用来代替 useEffect 的自定义钩子的工作方式:

 function useDidUpdateEffect(fn, inputs) {
  const didMountRef = useRef(false);

  useEffect(() => {
    if (didMountRef.current) {
      return fn();
    }
    didMountRef.current = true;
  }, inputs);
}

感谢@Tholle 建议 useRef 而不是 setState

原文由 Estus Flask 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是一个自定义挂钩,它只提供一个布尔标志来指示当前渲染是否是第一个渲染(当组件被安装时)。它与其他一些答案大致相同,但您可以在 useEffect 或渲染函数或您想要的组件中的任何其他位置使用标志。也许有人可以提出一个更好的名字。

 import { useRef, useEffect } from 'react';

export const useIsMount = () => {
  const isMountRef = useRef(true);
  useEffect(() => {
    isMountRef.current = false;
  }, []);
  return isMountRef.current;
};

您可以像这样使用它:

 import React, { useEffect } from 'react';

import { useIsMount } from './useIsMount';

const MyComponent = () => {
  const isMount = useIsMount();

  useEffect(() => {
    if (isMount) {
      console.log('First Render');
    } else {
      console.log('Subsequent Render');
    }
  });

  return isMount ? <p>First Render</p> : <p>Subsequent Render</p>;
};

如果您有兴趣,这里有一个测试:

 import { renderHook } from '@testing-library/react-hooks';

import { useIsMount } from '../useIsMount';

describe('useIsMount', () => {
  it('should be true on first render and false after', () => {
    const { result, rerender } = renderHook(() => useIsMount());
    expect(result.current).toEqual(true);
    rerender();
    expect(result.current).toEqual(false);
    rerender();
    expect(result.current).toEqual(false);
  });
});

我们的用例是在初始道具指示应隐藏动画元素时隐藏它们。如果道具发生变化,在以后的渲染中,我们确实希望元素动画化。

原文由 Scotty Waggoner 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进