【问题标题】:Run Effect hook only when both dependencies change仅当两个依赖项都更改时才运行效果挂钩
【发布时间】:2019-11-14 19:46:12
【问题描述】:

我有一个 React 组件,它使用 useEffect 钩子获取数据,如下所示:

const cache = {key: "data-fetched-using-key"}
function Config({key, options}) {
    const [data, setData] = useState();
    useEffect(() => {
        const fetchedData; // fetch data using key and options
        setData(fetchedData);
        cache[key] = fetchedData;
    }, [key, options])
    return <p>{data}</p>;
}

每次keyoptions 更改时都会运行挂钩。但是,我也在本地缓存数据,并且只希望在 keyoptions 更改时运行效果(因为对于每个键/选项组合,数据将始终相同)。

有没有一种干净的方式来依赖 keyoptions 而不是 keyoptions 使用 React Hooks 的组合?

【问题讨论】:

  • 是的,有。你需要使用 useCallback 钩子。

标签: reactjs react-hooks


【解决方案1】:

您可以使用useRef() 创建这种逻辑。考虑以下示例和沙箱:https://codesandbox.io/s/react-hooks-useeffect-with-multiple-reqs-6ece5

const App = () => {
  const [name, setName] = useState();
  const [age, setAge] = useState();

  const previousValues = useRef({ name, age });

  useEffect(() => {
    if (
      previousValues.current.name !== name &&
      previousValues.current.age !== age
    ) {
      //your logic here
      console.log(name + " " + age);
      console.log(previousValues.current);

      //then update the previousValues to be the current values
      previousValues.current = { name, age };
    }
  });

  return (
    <div>
      <input
        placeholder="name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <input
        placeholder="age"
        value={age}
        onChange={e => setAge(e.target.value)}
      />
    </div>
  );
};

工作流程:

  1. 我们为要跟踪的两个值创建一个ref 对象, 在这种情况下,它是 nameage。引用对象是previousValues
  2. useEffect 已定义,但我们不提供任何依赖项。 相反,只要有状态更改,我们就让它执行 nameage
  3. 现在在useEffect 内部我们有条件逻辑来检查是否 nameage 的先前/初始值都不同于 它们对应的状态值。如果他们很好,我们执行 我们的逻辑(console.log)
  4. 最后在执行完逻辑后,将引用对象(previousValues)更新为当前值(state)

【讨论】:

    【解决方案2】:

    为了在两个值都发生变化时运行效果,您需要利用之前的值并在键或选项发生变化时在钩子中比较它们。

    您可以编写一个usePrevious 挂钩并比较本文中提到的旧状态和以前的状态:

    How to compare oldValues and newValues on React Hooks useEffect?

    function usePrevious(value) {
      const ref = useRef();
      useEffect(() => {
        ref.current = value;
      });
      return ref.current;
    }
    
    const cache = {key: "data-fetched-using-key"}
    function Config({key, options}) {
        const [data, setData] = useState();
        const previous = usePrevious({key, options});
        useEffect(() => {
            if(previous.key !== key && previous.options !== options) {
                const fetchedData; // fetch data using key and options
                setData(fetchedData);
                cache[key] = fetchedData;
            }
        }, [key, options])
        return <p>{data}</p>;
    }
    

    【讨论】:

    • 很好,我也很喜欢这个。 :)
    • 这太好了,谢谢!肯定会记得 usePrevious :)
    【解决方案3】:

    所有提供的解决方案都很好,但是有一些更复杂的情况,例如,只有当依赖项 A 和 B 发生变化时才应该调用 useEffect 函数,而它也取决于 C 的值。

    所以我建议使用 useEffects 和中间状态的序列来为未来的逻辑提供更多空间。对所问问题的这种方法的实施将是:

    const cache = {key: "data-fetched-using-key"}
    function Config({key, options}) {
        const [data, setData] = useState();
    
        const [needsUpdate, setNeedsUpdate] = useState(()=>({key:false, option:false}));
    
        useEffect(()=>{
          setNeedsUpdate((needsUpdate)=>({...needsUpdate, key:true}));
        },[key])
    
        useEffect(()=>{
          setNeedsUpdate((needsUpdate)=>({...needsUpdate, options:true}));
        },[options])
    
        useEffect(() => {
          if (needsUpdate.key && needsUpdate.options){
            const fetchedData; // fetch data using key and options
            setData(fetchedData);
            cache[key] = fetchedData;
            setNeedsUpdate(()=>({key:false, option:false}));
          }
        }, [needsUpdate, key, options])
        return <p>{data}</p>;
    }
    
    

    通过这种方式,我们几乎可以在 useEffect 依赖项上应用任何逻辑,但是它也有自己的缺点,就是渲染周期要少。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 2021-02-25
      • 2018-08-05
      • 1970-01-01
      相关资源
      最近更新 更多