【问题标题】:Should I use useRef for storing one-time initialised data?我应该使用 useRef 来存储一次性初始化数据吗?
【发布时间】:2020-09-06 22:16:37
【问题描述】:

今天使用 react 的 ref 可能有点令人困惑。 回到类组件的时代,在文档中已经很清楚了。

我们应该主要将 refs 用于 DOM 元素

https://reactjs.org/docs/refs-and-the-dom.html

但是今天我们将钩子与功能组件结合在一起。 我们正在使用useRef钩子。

另外,这给我们带来了新的模式。使用 ref 来包含 callbacks,或任何我们想要保留(某种状态)但不需要重新渲染的 data。 它是一个强大的 API,也出现在文档中:

https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables

所以现在 ref 可以用于:

  1. 存储可变数据

  2. 一种记忆

但是这些文档相互矛盾。并在开发团队中造成许多错误和冲突。

文档说了两件事,这是一个问题。

那么,在这种情况下,“正确”的做法是什么?


const MyComponent = (props) => {
   const [myMap1, _] = useState(new Map());    // 1.
   const myMap2 = useMemo(()=> new Map(), []); // 2.
   const myMap3 = useRef(new Map());           // 3.

   ...
};

【问题讨论】:

    标签: javascript reactjs react-hooks memoization


    【解决方案1】:

    useMemo 是一种声明性 performance optimization 技术。

    声明性,因为它依赖于属于特定渲染的周围范围的状态或道具依赖关系,并自动(重新)创建记忆值。我们不必告诉useMemo 这样做。

    useRef 是一个 可变 存储框,用于存储任何值,例如值更新独立于当前渲染范围。

    useRef 没有任何依赖关系,因此不会自动更改任何值。您必须通过编写 ref.current = ... 手动完成此操作(DOM 节点是一个例外)。 这就是为什么您可以将useRef 视为进入势在必行世界的逃生口。

    现在,我们可以尝试混合他们的usage interchangeably 进行存储,例如:
    // instead of 
    const val = useMemo(() => 42, [myDep]); // 42 stands for some complex calculation
    // do this
    const ref = useRef();
    ref.current = 42 // assign 42 imperatively to ref somewhere in render
    
    甚至replaceuseRefuseState
    const [ref] = useState({current:null});
    ref.current = "hello";
    

    缺点:我们又回到了旧的 jQuery 时代:-)。操作必须强制设置,这意味着更多的手动工作和可能的错误。不可变的值操作也比突变更可预测(包括其他好处)。也就是说,为什么 React 中几乎所有东西都是不可变的。

    相反,在可能的情况下保持声明性(React 惯用语)并针对特定情况使用预期的优化工具是有意义的:

    • useState 声明式的不可变值,触发重新渲染
    • useMemo 用于声明性记忆 源自 state 和 props 的昂贵值
    • useRef 用于 可变 值或 DOM 节点 - 独立于渲染关闭范围,不需要 deps,不会触发重新渲染,更多手动命令式工作

    【讨论】:

    • 请注意,我已更改文档的第一个链接。我之前的链接有错误。您对文档之间的差异有何看法。这才是最重要的。
    • 您能否澄清一下,您认为哪些确切陈述相互矛盾?使用 react 类组件,您有一个隐式的 this 上下文来存储可变实例值。对于函数组件,情况并非如此,因此我们需要一个类似useRef 的 Hook 来实现此目的。无论是类还是函数:ref 仍然是一个盒子,可以在其中存储和修改任何值(DOM 节点、计算等)。所以是的:ref 有一个额外的功能组件用例。
    【解决方案2】:

    钩子 useRef 可用于存储任何值,例如,您有一个对象、数组或地图,您不想为每次重新渲染重新初始化 你可以使用 useRef 钩子。

     // this code will recreate the object in memory on each rerender
     const myObj = {foo: 'foo', bar: 'bar'}
    
     // here you have the same object in memory even after rerenders
     const refObj = useRef({foo: 'foo', bar: 'bar'})
    
    

    同样,useState 钩子可用于存储普通状态变量。

    当某个值依赖于代码中的另一个变量并且您只想在变量更改时更改值时,useMemo 很有用(在将 props 作为对象传递或将 memoized 对象传递给传递给上下文提供程序的 value prop 时很有用)。

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 2021-04-17
      • 1970-01-01
      • 1970-01-01
      • 2014-01-12
      • 1970-01-01
      • 2016-06-28
      相关资源
      最近更新 更多