反应:useState或useRef?

Hai*_*763 11 reactjs react-hooks

我读约阵营useState(),并useRef()在“ 鱼钩常见问题解答 ”,我糊涂了关于一些使用案例,似乎有useRef和useState解决方案的同时,我不知道哪条路是正确的方式。

关于useRef()的“挂钩常见问题”中:

“ useRef()钩不仅用于DOM引用。“ ref”对象是通用容器,其当前属性是可变的,并且可以保存任何值,类似于类的实例属性。”

使用useRef()

function Timer() {
  const intervalRef = useRef();

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    intervalRef.current = id;
    return () => {
      clearInterval(intervalRef.current);
    };
  });

  // ...
}
Run Code Online (Sandbox Code Playgroud)

使用useState()

function Timer() {
  const [intervalId, setIntervalId] = useState(null);

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    setIntervalId(id);
    return () => {
      clearInterval(intervalId);
    };
  });

  // ...
}
Run Code Online (Sandbox Code Playgroud)

这两个示例将具有相同的结果,但是哪个示例更好-为什么?

Eas*_*war 19

两者之间的主要区别是:

useState导致重新渲染,useRef不会。

它们之间的共同点是两者,useState并且useRef在重新渲染后可以记住它们的数据。因此,如果您的变量是决定视图图层渲染的变量,请使用useState。其他用途useRef

我建议阅读这篇文章

  • 另一个很大的区别是设置状态是异步的而设置引用是同步的。 (66认同)
  • 当您将 useRef 与本机 HTML 输入元素一起使用时,您的组件是不受控制的输入,而使用 useState 则其受控制的输入 (2认同)

gli*_*a93 14

useRef当您想要跟踪值更改但不想触发重新渲染或useEffect通过它触发重新渲染时非常有用。

大多数用例是当您有一个依赖于值的函数,但该值需要由函数结果本身更新时。

例如,假设您想要对某些 ​​API 结果进行分页:

const [filter, setFilter] = useState({});
const [rows, setRows] = useState([]);
const [currentPage, setCurrentPage] = useState(1);

const fetchData = useCallback(async () => {
  const nextPage = currentPage + 1;
  const response = await fetchApi({...filter, page: nextPage});
  setRows(response.data);
  if (response.data.length) {
    setCurrentPage(nextPage);
  }
}, [filter, currentPage]);
Run Code Online (Sandbox Code Playgroud)

fetchData正在使用currentPage状态,但响应成功后需要更新currentPage。这是不可避免的过程,但很容易导致Maximum update depth exceeded errorReact中的无限循环。例如,如果您想在加载组件时获取行,您需要执行以下操作:

useEffect(() => {
  fetchData();
}, [fetchData]);
Run Code Online (Sandbox Code Playgroud)

这是有问题的,因为我们使用状态并在同一函数中更新它。

我们想要跟踪currentPage但不想useCallback通过useEffect它的改变来触发。

我们可以通过以下方法轻松解决这个问题useRef

const currentPageRef = useRef(0);

const fetchData = useCallback(async () => {
  const nextPage = currentPageRef.current + 1;
  const response = await fetchApi({...filter, page: nextPage});
  setRows(response.data);
  if (response.data.length) {
     currentPageRef.current = nextPage;
  }
}, [filter]);
Run Code Online (Sandbox Code Playgroud)

我们可以在 的帮助下currentPage从 deps 数组中删除依赖关系,这样我们的组件就可以避免无限循环。useCallbackuseRef


Bid*_*Das 8

useState 和 useRef 之间的主要区别是 -

  1. 引用的值在组件重新渲染之间保持不变(保持不变),

  2. 使用 更新引用useRef不会触发组件重新渲染。但是,更新状态 c会导致组件重新渲染

  3. 引用更新是同步的,更新后的引用值立即可用,但状态更新是异步的——值在重新渲染后更新。

使用代码查看:

import { useState } from 'react';
function LogButtonClicks() {
  const [count, setCount] = useState(0);
  
  const handle = () => {
    const updatedCount = count + 1;
    console.log(`Clicked ${updatedCount} times`);
    setCount(updatedCount);
  };
  console.log('I rendered!');
  return <button onClick={handle}>Click me</button>;
}
Run Code Online (Sandbox Code Playgroud)

每次单击该按钮时,都会显示我渲染了!

然而,随着useRef

import { useRef } from 'react';
function LogButtonClicks() {
  const countRef = useRef(0);
  
  const handle = () => {
    countRef.current++;
    console.log(`Clicked ${countRef.current} times`);
  };
  console.log('I rendered!');
  return <button onClick={handle}>Click me</button>;
}
Run Code Online (Sandbox Code Playgroud)

我的渲染将仅被控制台记录一次


小智 5

基本上,我们在这些情况下使用UseState,其中状态值应该通过重新渲染进行更新。

当您希望信息在组件的生命周期内持续存在时,您将使用UseRef,因为它不适用于重新渲染。