【问题标题】:How to optimize my code with useMemo in React?如何在 React 中使用 useMemo 优化我的代码?
【发布时间】:2020-10-08 04:39:42
【问题描述】:

我在 React 中遇到了 useMemo() 钩子的情况。

我有一个名为a 的数组对象。该对象包含多个对象。这个数组很大。当它包含bc 对象时,a 看起来像a = [b,c]。我正在对数组a 进行大量计算。这是我的代码 sn-p:

    const computedValue = useMemo(() => {
         return a.map(key,() => {
           anotherHighComputationFunc(key);
         });
    },[a])

const anotherHighComputationFunc = useMemo((key) => {
        // ..... do some expensive computation
       return someValue;
},[key]);

如果a 的引用没有改变,我不会再次计算该值,我只是返回预先计算的值。如果a 的引用发生更改,那么我将查看数组a 以检查是否某个键已更改其在数组内的引用。如果某个键的引用没有改变,则返回该键的预计算值,否则对该键进行计算。

问题是钩子规则失败了,因为我在另一个钩子中使用了一个钩子。所以它给我一个错误。有没有其他方法可以在 2 个级别上进行记忆?

【问题讨论】:

  • 钩子可以在其他钩子中使用,但我怀疑问题出在 some “条件”钩子调用上,尽管我没有从你的 sn-p 中看到钩子在另一个钩子中被调用。能否提供更完整的代码示例?
  • @DrewReese 我相信问题是在 map 函数中调用 useMemo ,这是一个循环,React 要求避免在循环中使用钩子。
  • 也许,它被认为是在循环中调用(但您正在调用 memozied 回调)或嵌套函数(我认为是这个)。听起来您可以滚动自己的简单缓存。

标签: javascript arrays reactjs lodash


【解决方案1】:

useMemo() 钩子在这里对你没有帮助,因为它的缓存大小为 1,你不能在其他钩子中调用钩子。另外,你不需要记住函数,而是调用的结果。

您可以使用WeakMap 创建一个简单的记忆包装器,这将允许垃圾收集器在不需要时清理值。

注意:WeakMap 的键必须是对象。

const weakMemo = fn => {
  const map = new WeakMap();
  
  return obj => {
    if (map.has(obj)) return map.get(obj);
    
    const res = fn(obj);
    
    map.set(obj, res);
    
    return rs;
  }
};

// the useMemo is needed here to preserve the instance of the memoized function with the cached values
const computeKey = useMemo(() => weakMemo((key) => {
  // ..... do some expensive computation
  return someValue;
}), [anotherHighComputationFunc]);

const computedValue = useMemo(() => a.map(computeKey), [a, computeKey]);

【讨论】:

    【解决方案2】:

    Hook 的规则明确规定:不要在循环、条件或嵌套函数中调用 Hook。相反,请始终在 React 函数的顶层使用 Hooks。

    不要为 anotherHighComputationFunc 使用挂钩,而是创建一个 cache 对象,该对象存储函数的值,如果它在缓存对象内,则返回它。

    const cache = {};
    
    function anotherHighComputationFunc(key) {
       if (cache[key]) return cache[key];
    
        /** anotherHighComputation calculation here */
        cache[key] = anotherHighComputationValue;
        return anotherHighComputationValue
    } 
    
     const computedValue = useMemo(() => {
         return a.map(key,() => {
           anotherHighComputationFunc(key);
        });
    },[a])
    

    【讨论】:

    • 这是最好的方法。但这里的问题是我必须维护自己的缓存,这可能不如 useMemo 高效。如果有其他方法可以避免创建自己的缓存并使用一些已经实现的最佳记忆技术。
    • my own cache which may not be as efficient as useMemo is 是什么意思?对象查找具有O(1) 时间复杂度。您能详细说明more efficient 在这里的含义吗?
    • 高效我的意思是,必须进行一些定期的内存清理,以便我的内存不会大部分被缓存对象占用。正如 React 在其网站上提到的 useMemo:In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components
    • @unpredictable 有意义,然后只需 useRef 收集值并将其用作缓存。我已经更新了上面的代码。
    • 所谓的“规则”,即Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function.,无论如何都没有被违反。 anotherHighComputationFunc 不是钩子,它是钩子返回的值,“规则”不适用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多