【问题标题】:Access variables in a `useEffect` without triggering the effect when they get updated访问“useEffect”中的变量而不在更新时触发效果
【发布时间】:2020-05-11 09:23:50
【问题描述】:

我需要访问 useEffect 中的变量,但只有在其中一些更新时才触发该方法。

例如:

我想在data 更改时调用useEffect,但在saveTimeoutsaveMethod 更改时不调用。

以同样的方式,我想在我的组件卸载时调用 saveMethod,但我不能,因为它需要在依赖数组中,因此在每次更改 saveMethod 时调用它。

function SavingComponent({data, apiInfo}){
    [saveTimeout, setSaveTimeout] = useState(null);

    const saveMethod = useCallBack(()=>{
        clearTimeout(saveTimeout);

        // api call to save the data using apiInfo

    }, [data, saveTimeout, apiInfo])

    // Start a timer to save the data 2 seconds after it is changed (not working)
    useEffect(()=>{
        clearTimeout(saveTimeout);
        setSaveTimeout(setTimeout(saveMethod, 2000));
    }, [data, saveTimeout, saveMethod]);

    // Save immediately on dismount only (not working)
    useEffect(()=>{
      return ()=> { saveMethod(); }
    },[saveMethod])

    return (// some rendering)
}

这是我在其他情况下经常遇到的问题,并且不得不解决。通常使用自定义的usePrevious 方法。如果我感兴趣的道具没有改变,我会将道具的先前值与当前值进行比较并立即返回。

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

只有在某些依赖项更新时才调用useEffect 的正确方法是什么?

【问题讨论】:

  • 也许这与问题无关,但使用clearTimeout的方式类似于功能Debounce,可能更容易让您控制useEffect
  • 我在切换到 hooks 之前使用了 debounce。它会与 useCallBack 方法兼容吗?但是,是的,问题更多是关于如何处理这样的情况,超时只是几十个例子中的一个。
  • 我之前没有在钩子中使用debounce,但是在that one 下使用钩子看起来有类似的答案?尽管它有四个赞成票,但可能需要尝试确认...

标签: react-native use-effect


【解决方案1】:

首先建议使用useEffect 中使用的变量和函数作为依赖项,这是最佳实践。 This is a very good article written by Dan Abramov 深入探讨了 useEffect 的工作原理以及为什么需要遵循最佳实践。

现在回到你的情况。

我认为您不希望在设置 saveTimeout 时重新渲染组件,因此请改用 useState,您可以将 useRef 用于该 saveTimeout = useRef(null),这样您就可以从依赖项中删除 saveTimeout

如果您不希望 saveMethod 成为依赖项,您可以将其移动到 useEffect 中,以便您也可以将其从依赖项中删除。

function SavingComponent({data, apiInfo}){
    const saveTimeout = useRef(null);

    // move saveMethod inside
    useEffect(()=>{
        const saveMethod = ()=>{
            clearTimeout(saveTimeout.current);
            // api call to save the data using apiInfo
        }
        // saveMethod will be called after 2 seconds
        saveTimeout.current = setTimeout(saveMethod, 2000);
    }, [data]);

    // move saveMethod inside
    useEffect(()=>{
        const saveMethod = ()=>{
            // api call to save the data using apiInfo
        }
        // saveMethod will be call when the component unmounted
        // But make sure you are not update any state inside saveMethod
        return saveMethod
    },[])

    return (// some rendering)
}

【讨论】:

  • 这篇文章非常有趣!它指的是useReducer,而不是useRef。当我需要访问超出我的useEffect 范围但不应该在更改时触发它的变量时,您是否建议使用useRef
  • @RyanPergent 在文章中提到您可以将函数移动到useEffect 中,以便将其从依赖项中删除,还有另一种方法是使用useReduceruseRef 是另一个方面,当您想通过更改状态更改值并重新渲染组件时使用它(文章也解释了)
  • 是的,我读了整本书。将函数放在useEffect 里面,当你需要在更多地方使用它时,它不起作用,useReducer 似乎过于复杂。您对useRef 的建议似乎既简单又有效,这就是为什么我要问您是否普遍推荐它(或者它是否有某种警告)。
  • 在您给出的示例中,在卸载时调用saveMethod,您省略了依赖项。但是,我的问题特别是我有依赖项阻止我使用 useEffect 进行卸载。有没有没有省略依赖的例子?
  • 第二个useEffect没有省略任何依赖,因为你在useEffect 内部创建saveMethod useEffect 将不再依赖saveMethod 方法
猜你喜欢
  • 2023-01-26
  • 2021-07-03
  • 2020-11-23
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 2021-10-17
  • 1970-01-01
相关资源
最近更新 更多