React 的 useRef 钩子不接受函数?

Sti*_*nky 3 javascript reactjs react-hooks

我习惯将函数传递给 useState,这样我就不会创建不必要的对象:

useState(() => /* create complex obj */)
Run Code Online (Sandbox Code Playgroud)

我预计 useRef 会以相同的方式工作,但下面返回一个函数,而不是调用它一次来初始化,然后返回先前创建的对象。

useRef(() => /* create complex obj */).current
Run Code Online (Sandbox Code Playgroud)

我想人们可以做这样的事情,但看起来不太干净。

const myRef = useRef();
useEffect(() => {
    myRef.current = /* create complex obj */;
}, []);
Run Code Online (Sandbox Code Playgroud)

我错过了什么还是它真的是 useRef 的限制?

更新

澄清一下,这是使用 useState 和 useRef 的常用方法:

useState(createSimpleInitialValue());
useRef(createSimpleInitialValue());
Run Code Online (Sandbox Code Playgroud)

对于每次渲染,您都花时间创建一个初始值,该值将在第一次渲染后被丢弃。这对于简单的对象来说并不重要,但对于复杂的对象有时可能会成为问题。useState 有一个解决方法:

useState(() => createComplexObj());
Run Code Online (Sandbox Code Playgroud)

我们传递的不是对象,而是函数。React 将在第一次渲染时调用该函数,但不会在后续渲染中调用该函数,因此您只需构建该对象一次。我希望 useRef 有这样的功能,但是当你传递一个函数时,它只存储该函数。文档没有提到 useRef 可以接受一个函数,但我希望仍然有一些内置的方法来做到这一点。

Rob*_*ond 5

正如我在评论中指出的,React Github 存储库上已经对此进行了相当长的讨论。建议了几种解决方法,包括使用useMemo空依赖数组的解决方法 - 但 Dan Abramov(React 核心开发人员之一)在此评论中特别不建议这样做,因为

\n
\n

useMemo不建议[]用于此用例。将来,我们可能会遇到这样的用例:我们删除useMemo值 \xe2\x80\x94 以释放内存或减少我们保留的内存量,例如隐藏项目的虚拟滚动。您不应该依赖useMemo保留值。

\n
\n

但他接着提供了他自己推荐的解决方法:

\n
\n

我们对此进行了更多讨论,并决定将此模式作为昂贵对象的推荐:

\n
\n

我用一个代码片段代表了下面的要点,同时删除了特定于问题提出者用例并匹配简短代码的细节(如果感兴趣,仍然可以在上面的 Github 链接中看到)您问题中的示例更好:

\n
function MyComponent() {\n  const myRef = useRef(null)\n\n  function getComplexObject() {\n    let complexObject = myRef.current;\n    if (complexObject !== null) {\n      return complexObject;\n    }\n    // Lazy init\n    let newObject = /* create complex obj */;\n    myRef.current = newObject;\n    return newObject;\n  }\n\n  // Whenever you need it...\n  const complexObject = getComplexObject();\n  // ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您希望看到的,这里的想法很简单,尽管代码有点冗长:我们将 ref 值初始化为,null然后,每当需要时,如果 ref 成立,则计算它并将null其存储在 ref 中,否则使用存储在 ref 中的值。这只是一个非常基本的记忆,但与 React 不同的是useMemo,它完全保证在第一次渲染后不会重新计算值。

\n