如何从头开始为 React 实现自己的 useMemo

IT技术 javascript reactjs memoization internals
2021-04-26 08:44:56

基本上是这样的:

function MyComponent() {
  let [count, setCount] = useState(1)
  let memo = useMyMemo(() => new MyClass)

  return <div onClick={update}>{count}</div>

  function update() {
    setCount(count + 1)
  }
}

function useMyMemo(fn) {
  // what to do here?
}

class MyClass {

}

我想为每个组件实例useMyMemo只返回类的 1个实例我如何设置它以实现它而不诉诸使用任何现有的 React 钩子?如果没有 React 钩子就不可能,他们为什么不呢?如果只能通过访问内部 API 来实现,您会怎么做?

作为奖励,了解如何传递属性依赖项以及如何使用它来确定备忘录是否应该失效将很有帮助。

1个回答

我认为您正在描述useMemo已经如何工作,假设您[]作为依赖项参数传递它应该已经为 的MyClass每个实例创建了一个实例MyComponent但是,文档说 的未来版本useMemo将不能保证该值仅被调用一次,因此您可能想尝试useRef.

const memo = useRef(null);
if (!memo.current) {
  memo.current = new MyClass()
}

如果您希望它MyClass在依赖项更改时创建一个新实例,您将不得不使用useMemo(并接受该值偶尔可能无效的可能性),或者与之前的值进行自己的浅层比较。像这样的东西:

const useMyMemo = (create, dependencies) => {
  const val = React.useRef(create());
  const prevDependencies = React.useRef([]);
  if (!shallowEquals(dependencies, prevDependencies.current)) {
    val.current = create();
    prevDependencies.current = [...dependencies];
  }
  return val;
};

我会把 的实现留给shallowEquals你,但我相信 lodash 有一个。

现在你真的要求一个不使用任何 React 钩子的函数,而我的使用useRef. 如果您不想要useRef,您可以创建自己的简单记忆功能,无论 发生什么变化,它始终返回相同的指针.current