反应:useState 还是 useRef?

新手上路,请多包涵

我正在阅读有关 React useState()useRef() 的“ Hooks FAQ ”,我对一些似乎同时使用 useRef 和 useState 解决方案的用例感到困惑,而且我不确定哪种方式正确。

来自 关于 useRef() 的“Hooks FAQ”:

“useRef() Hook 不仅适用于 DOM refs。‘ref’ 对象是一个通用容器,其当前属性是可变的并且可以保存任何值,类似于类上的实例属性。”

使用 useRef()

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

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

  // ...
}

使用 useState()

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

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

  // ...
}

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

原文由 Haim763 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 782
2 个回答

两者的主要区别是:

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

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

我建议阅读这篇 文章

原文由 Easwar 发布,翻译遵循 CC BY-SA 4.0 许可协议

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]);

fetchData 正在使用 currentPage 状态,但它需要更新 currentPage 成功响应后。这是不可避免的过程,但在 React 中很容易导致无限循环 aka Maximum update depth exceeded error 。例如,如果你想在加载组件时获取行,你想做这样的事情:

 useEffect(() => {
  fetchData();
}, [fetchData]);

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

我们想跟踪 currentPage 但不想触发 useCallbackuseEffect 的变化。

我们可以使用 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]);

我们可以在 --- 的帮助下从 useCallback deps 数组中删除 currentPage useRef ,这样我们的组件就可以从无限循环中保存下来。

原文由 glinda93 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进