为什么需要 useRef 而不是可变变量?

IT技术 javascript reactjs react-hooks
2021-02-01 02:44:37

我已经阅读了使用效果的完整指南 - 在过度react时逆流而上。

例子表明,如果我们想要获取最新的count,我们可以使用useRef保存可变变量,并在异步函数 laster 中获取它:

function Example() {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);

  useEffect(() => {
    // Set the mutable latest value
    latestCount.current = count;
    setTimeout(() => {
      // Read the mutable latest value
      console.log(`You clicked ${latestCount.current} times`);
    }, 3000);
  });
  // ...
}

但是,我可以通过在组件函数之外创建一个变量来做同样的事情,例如:

import React, { useState, useEffect, useRef } from 'react';

// defined a variable outside function component
let countCache = 0;

function Counter() {
  const [count, setCount] = useState(0);
  countCache = count;       // set default value

  useEffect(() => {
    setTimeout(() => {
      // We can get the latest count here
      console.log(`You clicked ${countCache} times (countCache)`);
    }, 3000);
  });
  // ...
}

export default Counter;

这两种方法都实用吗,或者如果我在函数组件之外定义变量有什么不好的吗?

1个回答

useRef将为每个组件分配一个引用,而在函数组件范围之外定义的变量只会分配一次

useRef 引用生命周期是组件的生命周期(当组件卸载时它“死亡”,而 JS 变量是作用域阻塞的)。

因此,定义组件范围之外的常量用途变量:

// This statement will only called once
const DEFAULT_VALUE = 5;

function Component() {
  // use DEFAULT_VALUE.
}

在组件的作用域内定义相同的语句,将在每次渲染时重新定义它:

// We can do better
function Component() {
  // Redefined on every render
  const DEFAULT_VALUE = 5;
}

现在的问题:

首先,我们实际上无法反映使用外部作用域变量更改的 UI,因为更改它们不会触发渲染(只有 React API 可以)。

因此反射值就是它的闭合值。

let countCache = 0;

function Counter() {
  ...
  countCache = 0;

  useEffect(() => {
    countCache = count;
  });
  ...

  // closure value of countCache
  return <div>{countCache}</div>
}

现在,外部作用域变量的特殊之处在于它们对于module本身是全局的,因此使用它的值对于引用它的所有组件(在module中)是全局的。

例如,如果您想计算组件在整个应用程序生命周期中安装的次数,请在安装时增加内部变量useEffect(找不到任何其他可能的用例)。

let howMuchMounted = 0;

function Component() {
  useEffect(() => { howMuchMounted += 1, [] };
}

为了反映外部变量和useRef引用的差异,在下一个示例中,在单击按钮时,您可能会注意到variable两个组件都是全局的,而reference始终更新为当前状态值。

import React, { useEffect, useRef, useReducer } from "react";
import ReactDOM from "react-dom";

// defined a variable outside function component
let countCache = 0;

function Counter() {
  const [num, count] = useReducer((num) => num + 1, 0);

  const countRef = useRef(count);

  useEffect(() => {
    // set count value on count change
    countCache = num;
    countRef.current = num;
  }, [num]);

  return (
    <>
      <button onClick={count}>Count</button>
      <h3>state {num}</h3>
      <h3>variable {countCache}</h3>
      <h3>reference {countRef.current}</h3>
    </>
  );
}

export default function App() {
  return (
    <>
      <Counter />
      <hr />
      See what happens when you click on the other counter
      <hr />
      <Counter />
    </>
  );
}

请参阅有关useEffect用例后续问题,在使用useRef内部引用时有许多常见错误useEffect

编辑 useRef 与变量

我在组件中添加了另一个计数器,即 , counterOnecounterTwo并在函数外创建了两个变量,即cacheCounterOnecacheCounterTwo`。不过,我并没有发现什么奇怪的地方。看起来不错……你能给我更多提示吗?
2021-03-15 02:44:37
我给出了错误的代码。现在我countCache = 0;countCache = count;. 结果显示与 相同useRef,也可以<div>{countCache}</div>在渲染中使用
2021-03-17 02:44:37
我添加了一个例子检查一下
2021-04-08 02:44:37
答案仍然相同,尝试制作多个计数器,看看会发生什么。
2021-04-14 02:44:37
我发现这个答案只是解释了全局变量与局部变量的基本差异。每当组件死了,它的局部范围变量也死了。当您有一个文件承载所有微小的相关组件时,全局变量非常有用,这些组件引用了一些共享变量,例如按钮主题、翻译、基于颜色的设备等,因为当这些微小的任何一个时全局变量不会死亡或重新初始化组件重新渲染。
2021-04-14 02:44:37