【React】useState 和 useRef:项目开发中该如何选择

如果你正踏入用 React 进行网页开发的世界,那你可能已经遇到了像 useStateuseRef 这样的术语。这两个 Hook 在构建交互性和动态组件时起着至关重要的作用。

下面,我们将探讨它们是什么,它们的功能,它们的区别,并通过一些易于理解的例子来具体说明应用场景。

useState: 反应式管理状态

当涉及到在函数式 React 组件中管理状态时,useState 就像是最有价值的球员(MVP)。它让你能够添加状态管理功能,使组件具有反应性并且视觉上可更新。

让我们看看这段小代码:

js 复制代码
import React, { useState } from 'react';

function Counter() {
  // 声明状态变量 'count' 和用于更新它的函数 'setCount'
  const [count, setCount] = useState(0);

  const increment = () => {
    // 使用 'setCount' 函数更新 'count' 状态
    setCount(count + 1);
  };

  // 渲染包含当前计数和一个递增按钮的 div
  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={increment}>递增</button>
    </div>
  );
} 

在这里,我们使用 useState(0) 声明了一个状态变量 count。点击"递增"按钮会更新状态并触发重新渲染。

那么当值重新渲染时会发生什么?

在重新渲染期间,状态保持其值,在渲染之间保持一致。React 高效地比较当前和前一状态以作出必要的更新。

useRef: 不触发重新渲染

不同于 useStateuseRef 在其值改变时不会触发重新渲染。这对于保持对 DOM 元素的持久引用或存储值而不立即产生视觉反应非常有用。

让我们通过一个输入框的例子来具体说明:

js 复制代码
import React, { useRef, useEffect } from 'react';

function AutoFocusInput() {
  // 创建一个存储输入元素的引用
  const inputRef = useRef();

  // `useEffect` 用于处理函数式组件中的副作用
  useEffect(() => {
    // 当组件挂载时聚焦输入元素
    // 空依赖数组确保它仅运行一次
    inputRef.current.focus();
  }, []);
  
  // 渲染带有引用的输入元素
  return <input ref={inputRef} />;
}

在这个例子中,useRef 创建了 inputRef,这是一个在渲染之间持久存在的引用。即使组件重新渲染,inputRef 也保持不变。

那么当值重新渲染时会发生什么?

在上面的例子中,inputRef 在重新渲染期间不受影响,即使组件发生变化也能保证稳定性。

那什么时候选择 useRef 而不是普通变量呢?

你可能会疑惑为什么使用 useRef 而不是普通的 let 变量?关键在于 useRef 的独特属性使其与众不同:

  • 渲染之间的持久性 :与每次渲染都会被重新创建的 let 变量不同,useRef 在渲染之间保持其值,确保持久性。
  • 避免不必要的重新渲染 :修改 let 变量,即使没有视觉变化,也可能触发不必要的重新渲染。useRef 通过不引起重新渲染来避免这种情况。

选择 useRef 在需要在渲染之间保持值并且避免不必要的重新渲染的情况下是一种更为高效的方法。

forwardRef: 在组件间共享引用

有时候,你需要从父组件向子组件传递一个引用。这时 forwardRef 就派上了用场,允许使用 useRef 将引用传递给子组件。

让我们看一个例子:

js 复制代码
import React, { forwardRef, useRef, useImperativeHandle } from 'react';

// 子组件
const ChildComponent = forwardRef((props, ref) => {
  // 声明一个内部引用变量用于输入元素
  const internalRef = useRef();

  // 使用 `useImperativeHandle` 向父组件暴露 focus 函数
  useImperativeHandle(ref, () => ({
    focus: () => {
      // 在内部引用上调用 focus 函数
      internalRef.current.focus();
    }
  }));

  // 渲染带有内部引用的输入元素
  return <input ref={internalRef} />;
});

// 父组件
function ParentComponent() {
  // 在父组件中创建一个引用
  const childRef = useRef();

  // 在父组件中触发 focus 函数的函数
  const handleButtonClick = () => {
    childRef.current.focus();
  };

  return (
    <div>
      {/* 使用引用渲染子组件 */}
      <ChildComponent ref={childRef} />

      {/* 触发子组件中 focus 函数的按钮 */}
      <button onClick={handleButtonClick}>聚焦输入框</button>
    </div>
  );
}

在这个例子中,forwardRef 从父组件 (ParentComponent) 向子组件 (ChildComponent) 传递一个引用,允许直接访问输入框的聚焦函数。

关键差异与选择合适的工具

  • useState: 适用于管理会触发组件重新渲染的状态。非常适合那些状态变化要求视觉更新的交互性和动态组件。
  • useRef: 对于维持对 DOM 元素的持久引用或存储值而不引起重新渲染非常有用。最适合直接操作 DOM 或者不希望触发重新渲染的情况。

记住,在同一个组件中可以同时使用这两个 Hook 来解决不同的需求。理解何时以及如何应用每一个 Hook 对有效的 React 开发至关重要。

总结来说...

如果你想更新数据并导致用户界面更新,那就选择 useState 。如果需要在整个组件生命周期内更改数据而不触发不必要的渲染,那么 useRef 就是你的首选方案。

希望这篇文章能帮助你了解在 React 开发中 useStateuseRef 之间的区别。尝试在你的项目中运用这些概念,看看它们如何提升你的开发技能。

如果你有任何问题、建议或修正意见,请在评论区留言。

如果你想了解更多有关 React Hooks 的详细信息和示例,请查阅官方的 React 文档

相关推荐
ZC跨境爬虫5 分钟前
Apple官网复刻第二阶段day_6:(统一页脚模块封装+CSS公共复用体系落地)
前端·css·ui·重构·html
恋猫de小郭7 分钟前
Flutter 凉了没?Flutter 2026 的未来行程和规划,一些有趣的变化
android·前端·flutter
Beginner x_u9 分钟前
前端手动实现大文件分片上传调度层:分片计算、并发上传与断点续传
前端·状态模式·断点续传·大文件分片上传
胖纳特14 分钟前
Nextcloud 文件预览困局与破局:集成 BaseMetas Fileview 实现全格式在线预览
前端·后端
一个心烑14 分钟前
Layui结合springboot读取返回值,前端展示简单示例
前端·spring boot·layui
天天向上102414 分钟前
openlayers 加载Shapefile文件
前端·javascript·html
亿元程序员17 分钟前
手工拼豆有风险?手把手教你开发个电子版的
前端
wuxianda103020 分钟前
苹果App上架4.3a问题3天解决方案汇报总结
开发语言·javascript·uni-app·ecmascript·ios上架·苹果上架
hhhhhh_we21 分钟前
再定义“皮肤人格”:从Baumann 16型分型到预颜美历的AI时序人格
前端·图像处理·人工智能·python·aigc
琹箐21 分钟前
今天吃什么干什么随机生成
javascript·css·css3