等效于组件外部的React.useMemo

时间:2019-09-11 20:01:19

标签: javascript reactjs

我真的很喜欢React的useMemo hook的API,您可以在其中编写一个函数并在数组中列出其依赖项:

id  partner met id1 id2 id3 id4 id5 id6 id7 id8 id9 id10
id1  id10   1   NA  NA  NA  NA  NA  NA  NA  NA  NA  1
id2  id6    0   NA  NA  NA  NA  NA  0   NA  NA  NA  NA
id3  id7    0   NA  NA  NA  NA  NA  NA  0   NA  NA  NA
id4  id9    1   NA  NA  NA  NA  NA  NA  NA  NA  1   NA
id5  id8    1   NA  NA  NA  NA  NA  NA  NA  1   NA  NA
id6  NA     NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
id7  NA     NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
id8  NA     NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
id9  NA     NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA
id10 NA     NA  NA  NA  NA  NA  NA  NA  NA  NA  NA  NA

但是它有一个缺点,那就是只能在React函数组件中使用。如何使用可以在任何地方使用的相同API来实现某些东西?

澄清

我了解记忆是什么。我在专门谈论const memoizedValue = useMemo( () => computeExpensiveValue(a, b), [a, b] ); 钩子的API。多数记忆库都接受一个函数并返回该函数的记忆版本,而useMemo接受一个函数和参数列表并返回 value 。没有向用户公开的包装函数。

该API另一个有趣的部分是,即使每次调用都创建了一个新的匿名函数(在codepen上的完整示例),对useMemo的重复调用也将使用相同的缓存: / p>

useMemo

即使将三个不同的函数传递给import {useMemo} from 'react'; import ReactDOM from 'react-dom'; function computeExpensiveValue(a, b) { console.log('computing expensive value'); return a + b; } function MyComponent(props) { const {a, b} = props; const memoizedValue = useMemo( () => computeExpensiveValue(a, b), [a, b] ); return <div>{memoizedValue}</div> } for (const i of [1, 2, 3]) { ReactDOM.render(<MyComponent a={1} b={2} />, el); } ,这也只会记录一次“计算昂贵的价值”。显然,useMemo使用的不是函数对象,而是缓存对象,这是其API真正有趣的部分。

1 个答案:

答案 0 :(得分:0)

这个概念叫做备忘录,它有很多用javascript实现的方法,这里是一种流行的https://github.com/medikoo/memoizee#readme

这是useMemo相同api的幼稚实现

const memorizedResults = new Map();
const useMemo = (fn, deps) => {
  // there are two unique factors to the computation, first the function itself then the dependencies

  // First memorize results based on FN
  const memorizedResultsBasedOnFn =
    memorizedResults.get(fn) ||
    (memorizedResults.set(fn, new Map()) && memorizedResults.get(fn));

  // Then get/set results based on dependencies to each individual function
  return (
    memorizedResultsBasedOnFn.get(deps) ||
    (memorizedResultsBasedOnFn.set(deps, fn()) &&
      memorizedResultsBasedOnFn.get(deps))
  );
};

const someExpensiveComputation = n => {
  console.log('n', n);
  return n;
};

const f = () => someExpensiveComputation(10);
const anotherF = () => someExpensiveComputation(20);

const deps = [5];
const result1 = useMemo(f, deps); // These two will log n only once, meaning that f was called only once
const result2 = useMemo(f, deps);
const result3 = useMemo(f, [3]);
const result4 = useMemo(anotherF, deps);

// as expected will be 10 10 10 20 and 10 will be logged only twice
console.log(result1, result2, result3, result4); 

在实际的实现中,您将使用WeakMap而不是Map,并且需要确保无论调用useMemo多少次,缓存的大小都不会无限期增加。