【问题标题】:Triggering useEffect only certain conditions仅在特定条件下触发 useEffect
【发布时间】:2021-01-24 20:47:59
【问题描述】:

我对useEffect有基本的了解。如果没有第二个参数(依赖数组),它会在每个渲染上运行。使用空数组,它在第一次渲染时运行。使用数组中的参数,只要某些参数发生变化,它就会运行。

假设我有两个依赖项的 useEffect(来自 GraphQL 查询):result.dataresult.loading。如果result.data 更改并且result.loading 为假,我希望useEffect 运行。目的是例如更新 Redux 存储:

useEffect(() => {
  if (result.loading) return;
  dispatch(updatePhotos([...photos, ...result.data.photos]));
}, [result.data, result.loading]);

但有一个问题:我必须将photos 包含在依赖项列表中。但是photos变量会在其他地方更新,并再次触发这个useEffect。

如何仅在这两个变量发生变化时才运行 useEffect?

我当然可以使用 useState 来存储变量 resultFetched,在 useEffect 中将其设置为 true,然后仅当它是 false 时才调度。但在某些时候,我必须将其改回true,然后useEffect 再次运行,因为我无法手动更改result.dataresult.loading

当需要处理大量变量时,我不知道如何在这些情况下正确使用 useEffect。

目前我正在构建无限滚动照片列表,其中列表通过 GraphQL 部分加载。但是当用户打开一些照片并最终返回照片列表时,它会从 Redux 恢复到与打开照片之前相同的状态和滚动位置。

我花了无数个小时试图让它发挥作用,但是这个 useEffect 东西破坏了我的每一次尝试。 :) 它们总是在我希望它们触发之前被触发,因为有太多变化的变量。

另外,有时我想在useEffect 中运行一个函数(添加到依赖数组的函数),我使用useCallback 为该函数存储它。但是我还必须将函数使用的所有变量添加到 useCallback 的依赖数组中,因此当这些变量发生变化时,函数会重新生成。这意味着useEffect 突然又运行了,因为依赖数组中的函数发生了变化。

真的没有办法使用useEffect中的函数/变量,没有它们来触发useEffect吗?

【问题讨论】:

    标签: javascript reactjs typescript use-effect


    【解决方案1】:

    您可以在同一个组件中拥有两个单独的 useEffect 函数,它们将彼此独立工作。一张用于照片,一张用于数据加载。我希望这个例子能帮助你理解这一点。

    import React, { useState, useEffect } from "react";
    import ReactDOM from "react-dom";
    
    function App() {
      const [count, setCount] = useState(0);
      const [count2, setCount2] = useState(0);
      const [step, setStep] = useState(1);
    
      useEffect(() => {
        const id = setInterval(() => {
          setCount((c) => c + step);
        }, 1000);
        return () => clearInterval(id);
      }, [step]);
    
      useEffect(() => {
        const id = setInterval(() => {
          setCount2((c) => c + step);
        }, 1500);
        return () => clearInterval(id);
      }, [step]);
    
      return (
        <div>
          <h1>{count}</h1>
          <h1>{count2}</h1>
          <input value={step} onChange={(e) => setStep(Number(e.target.value))} />
        </div>
      );
    }
    ReactDOM.render(<App />, document.getElementById("container"));
    

    请参考沙盒中的这个例子 https://codesandbox.io/s/react-playground-forked-6h0oz

    【讨论】:

      【解决方案2】:

      这完全取决于 updatePhotos 的工作方式。如果这会创建一个动作,那么问题是您在错误的位置创建了新状态。此处不应使用以前的 photos 值,因为正如您所指出的那样,这会导致依赖。

      相反,您的 reducer 将拥有您可以使用的旧照片值,您只需将新的请求数据传递给您的 reducer。

      这里有更详细的描述:https://overreacted.io/a-complete-guide-to-useeffect/#decoupling-updates-from-actions

      【讨论】:

      • 是的,你是对的。这解决了 Redux 的问题,谢谢 :)
      猜你喜欢
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-10
      • 2018-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多