【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 文档

相关推荐
前端百草阁9 分钟前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜10 分钟前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund40411 分钟前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish11 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
zwjapple11 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five12 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序12 分钟前
vue3 封装request请求
java·前端·typescript·vue
临枫54113 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript
酷酷的威朗普14 分钟前
医院绩效考核系统
javascript·css·vue.js·typescript·node.js·echarts·html5
前端每日三省14 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript