React面试题,useRef和普通变量的区别

在React中,useRef 和普通的变量(如 let 或 const)在行为和用途上有很大的不同。以下是 skipFirst = useRef(true) 和直接使用 let skipFirst = true 的效果对比:

useRef(true) 的效果

tsx 复制代码
const skipFirst = useRef(true);
  1. 持久性:

    • useRef 创建的引用对象在组件的整个生命周期内保持不变。也就是说,skipFirst.current 的值会在每次组件渲染时保持一致,不会因为组件的重新渲染而丢失。
    • 例如,如果你在第一次渲染时将 skipFirst.current 设置为 false,那么在后续的渲染中,skipFirst.current 仍然是 false。
  2. 不触发重新渲染:

    • 修改 useRef 的值(如 skipFirst.current = false)不会触发组件的重新渲染。这使得 useRef 非常适合存储不需要触发重新渲染的值。
  3. 跨渲染保持状态:

    • useRef 的值在组件的每次渲染之间保持不变,这对于存储如计数器、标记等状态非常有用,尤其是在需要跨渲染保持状态的场景中。

直接使用 let skipFirst = true 的效果

tsx 复制代码
let skipFirst = true;
  1. 非持久性:

    • 使用 let 或 const 定义的变量在每次组件渲染时都会重新初始化。也就是说,每次组件重新渲染时,skipFirst 都会被重新设置为 true。
    • 例如,如果你在第一次渲染时将 skipFirst 设置为 false,那么在组件重新渲染时,skipFirst 仍然会被重新初始化为 true。
  2. 触发重新渲染:

    • 修改普通变量的值(如 skipFirst = false)不会直接触发组件的重新渲染,但这种变量的值在每次渲染时都会被重新初始化,因此无法保持状态。
  3. 无法跨渲染保持状态:

    • 普通变量在每次组件渲染时都会被重新初始化,无法保持跨渲染的状态。这使得它们不适合用于存储需要跨渲染保持的状态。

示例对比

假设我们有一个组件,需要在第一次渲染时跳过某个副作用,但后续渲染时执行该副作用。我们分别使用 useRef 和普通变量来实现:

使用 useRef
tsx 复制代码
import { useEffect, useRef } from 'react';

function MyComponent() {
  const skipFirst = useRef(true);

  useEffect(() => {
    if (skipFirst.current) {
      skipFirst.current = false;
      return;
    }
    console.log('This effect runs after the first render');
  }, []);

  return <div>My Component</div>;
}
  • 效果 :skipFirst.current 在第一次渲染时为 true,跳过副作用。后续渲染时,skipFirst.current 保持为 false,副作用会执行。
使用普通变量
tsx 复制代码
import { useEffect } from 'react';

function MyComponent() {
  let skipFirst = true;

  useEffect(() => {
    if (skipFirst) {
      skipFirst = false;
      return;
    }
    console.log('This effect runs after the first render');
  }, []);

  return <div>My Component</div>;
}
  • 效果 :每次组件重新渲染时,skipFirst 都会被重新初始化为 true,因此副作用永远不会执行。

总结

  • useRef:适合存储需要跨渲染保持状态的值,修改值不会触发重新渲染。
  • 普通变量(let/const):每次组件重新渲染时都会被重新初始化,无法保持跨渲染的状态。

在上述场景中,使用 useRef 是正确的选择,因为它可以确保 skipFirst 的值在组件的整个生命周期内保持一致,从而实现跳过第一次渲染的效果。

相关推荐
Dwzun11 分钟前
基于SpringBoot3+Vue3的油莎豆种植管理系统
java·前端·vue.js·spring boot·后端·python·计算机网络
小码哥_常6 小时前
一套自己部署的 IM,客户端是同一份 Flutter
前端·后端
蜗牛攻城狮8 小时前
微前端四大方案选型对比与最佳实践:qiankun、micro-app、wujie、Module Federation
前端·微前端·qiankun·前端架构·micro-app·wujie
她说可以呀10 小时前
Vue插槽
前端·javascript·vue.js
qq_4480111610 小时前
Vue + Jinja2两套模版与法冲突造成undefinedError
前端·javascript·vue.js
aixingpan10 小时前
aixingpan.cn API开发文档:前端查询夏令时和时区接口指南
前端·php
2601_9583529011 小时前
23.5×19mm 换掉一整条音频链?|A-68 集成了什么:ADC / DAC / 24.576MHz 时钟 / AEC / 波束降噪,主控仅需 6 根线
前端·音视频·ai降噪·回声消除·语音模块
志尊宝11 小时前
AI原生前端开发(039):AI辅助的Nuxt 4全栈开发
前端·vue.js·ai-native
FRing0312 小时前
JavaScript入门到精通三十二(深拷贝、浅拷贝、递归函数)
开发语言·前端·javascript
excel12 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端