React useEffect() 仅在具有依赖项的第一次渲染时运行

Die*_*sel 10 typescript reactjs react-hooks

对此还有其他几个 SO 问题,答案是通过 ESLint(我正在使用打字稿)消除依赖项投诉,或者做其他事情以仍然允许 useEffect 的第二个参数为[]. 但是,根据 React文档,不建议这样做。同样在反应 useEffect 文档下它说

如果传递一个空数组 ([]),则效果中的 props 和 state 将始终具有其初始值。虽然传递 [] 作为第二个参数更接近熟悉的 componentDidMount 和 componentWillUnmount 心智模型,但通常有更好的解决方案来避免过于频繁地重新运行效果。另外,不要忘记 React 将 useEffect 的运行推迟到浏览器绘制完成之后,所以做额外的工作不是问题。

我有以下代码:

  useEffect(() => {
    container.current = new VisTimeline(container.current, items, groups, options);
  }, [groups, items, options]);
Run Code Online (Sandbox Code Playgroud)

我希望它只运行一次。

是让它每次运行并useState跟踪它之前运行过的唯一方法:

  const [didLoad, setDidLoad] = useState<boolean>(false);

  useEffect(() => {
    if (!didLoad) {
      container.current = new VisTimeline(container.current, items, groups, options);
      setDidLoad(true);
    }
  }, [didLoad, groups, items, options]);
Run Code Online (Sandbox Code Playgroud)

Die*_*sel 9

我现在处理这个问题的方法是将适当的依赖项放在依赖项列表中。

因为我希望效果只运行一次,并且因为该效果只在组件第一次挂载时依赖于一些数据,所以省略这些依赖关系是完全没问题的。例如,groups道具可能会在稍后更改,但此效果不需要再次运行。

但是,作为一种习惯,我不会省略推荐的依赖项,我总是列出它们。如果我故意省略某些内容,我会添加一个 eslint ignore 语句(尽管还没有遇到需要这样做的情况)……只要您了解数据更改时发生的情况,这就是您想要遵循的任何约定并且效果确实/不运行。

但是,如果您确实想列出依赖项,我提出的代码也不是最佳解决方案:

 const [didLoad, setDidLoad] = useState<boolean>(false);

  useEffect(() => {
    if (!didLoad) {
      container.current = new VisTimeline(container.current, items, groups, options);
      setDidLoad(true);
    }
  }, [didLoad, groups, items, options]);
Run Code Online (Sandbox Code Playgroud)

当此效果运行时,我不想引起渲染。因此,我将使用 ref(不需要是依赖项)而不是使用状态。

 const timelineLoaded = useRef<boolean>(false);

  useEffect(() => {
    if (!timelineLoaded.current) {
      container.current = new VisTimeline(container.current, items, groups, options);
      timelineLoaded.current = true;
    }
  }, [groups, items, options]);
Run Code Online (Sandbox Code Playgroud)

  • @jpro 在生产代码中编写了数百个“useEffect”,我发现它在绝大多数情况下比类组件生命周期方法更强大且更容易,但在某些边缘情况下有点困难。就我个人而言,我对这种权衡很满意,其中很多只是经验。一旦掌握了一些边缘情况,解决它们就会变得更容易。我不同意这与我们之前的做法相比是有限制的,因为您可以用它实现完全相同的行为。它只是在极少数情况下多了一点样板,而在常见情况下代码却少得多。 (6认同)
  • 好悲伤。我已经专门编写功能组件一年多了,我对一些解决方法最终变得多么混乱感到非常沮丧。我是唯一一个发现 useEffect 极其有限的人吗? (4认同)