当前位置: 首页 > 知识库问答 >
问题:

React: useState还是useRef?

余天宇
2023-03-14

我正在“Hooks FAQ”上阅读ReactuseState()useRef(),我对一些似乎同时解决了useRef和useState问题的用例感到困惑,我不确定哪种方法是正确的。

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

"useRef()钩子不仅仅适用于DOM参考。"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);
    };
  });

  // ...
}

两个例子的结果相同,但哪一个更好?为什么?

共有3个答案

东方玉泽
2023-03-14

useRef在您希望跟踪值更改,但不希望触发重新渲染或useffect时非常有用。

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

例如,假设您想要分页一些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]);

getchData正在使用当前页面状态,但是在成功响应后需要更新当前页面。这是不可避免的过程,但它很容易导致无限循环,也就是React中的最大更新深度超过错误。例如,如果您想在加载组件时获取行,则需要执行以下操作:

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

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

我们希望跟踪currentPage,但不希望通过其更改触发useCallbackuseffect

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

我们可以在useRef的帮助下从useCallbackdeps数组中删除当前页面依赖项,这样我们的组件就可以从无限循环中保存下来。

杜君浩
2023-03-14

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

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

轩辕煌
2023-03-14

两者之间的主要区别是:

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

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

我建议读这篇文章。

 类似资料:
  • 根据yaml.org,正式文件扩展名为。 报价: 如果可能,请使用“.YAML”。 然而,在互联网上使用哪种扩展似乎存在分歧。如果您在web上查找示例,许多示例都使用未经许可的扩展名。

  • 问题内容: 在Java中,大多数基本类型都是带符号的(一位用于表示+/-),因此当我超出类型的限制时,我会得到意外的结果,例如负数。 有什么比使用BigInteger更好的解决方案了,因为BigInteger存在性能问题,并且您需要对基本算术使用类方法而不是语言运算符(以提高可读性)? 问题答案: 不,没有更好的解决方案。如果您使用的值不能为长整型或双精度型,那么您将需要使用诸如的引用类型,并且J

  • 问题内容: 我是JBoss(和Tomcat)的Java开发人员。去年,我不得不通过WebLogic进行开发,不得不说-我真的很想念JBoss。 由于我在WebLogic方面的经验很浅,因此我要问那些经验丰富的人:是否有理由在WebLogic上花钱?JBoss不会给您您所需要的一切吗? 问题答案: 我怀疑Weblogic被选中的原因是一个讨人喜欢的销售人员来花钱拜访经理,给他推销和嘿嘿,该公司正在使

  • 问题内容: 长话短说:什么都不做,什么也不接受(我应该使用哪一个?) CMD窗口: 请告诉我我在做错什么。 问题答案: 如果你不希望在运行程序时弹出终端窗口,请使用; 否则,使用 关于语法错误: 现在是3.x中的函数,请 改用:

  • 问题内容: 我以为使用绑定绑定javascript中的click事件,Chrome/Firefox似乎同意我的看法,但是我看到它是3个人在这里写的4次,所以它不可能是错字,而且我怀疑这是错别字巧合。 那么,为什么人们在写作不起作用时又写作呢? 问题答案: 因为某些浏览器(取决于DOCTYPE)对inline属性是可以容忍的,所以它似乎已经散布开了,甚至出现在JavaScript问题中,因为大小写很

  • 问题内容: 我将很快开始对我们演示文稿的一些自动化测试进行编码。似乎每个人都推荐WatiN和Selenium。您更喜欢ASP.NET Web表单的自动化测试中的哪一个?这些产品中哪个更适合您? 作为附带说明,我注意到WatiN 2.0自2008年3月以来一直在CTP中使用,是否有什么需要关注的? 问题答案: 只是想说,我目前正在努力在2009年第一季度的某个地方对WatiN 2.0进行Beta版测