面试官:修改 useRef 会引起 Re-Render 🤔🤔🤔

3,047 阅读5分钟

我们正在参加一个淘宝的比赛,如果对你有帮助,可以点击该链接进行换肤,为我们投上你的宝贵一票:

换肤地址

直接点击使用皮肤就可以啦,谢谢大家的支持!!!

在 React 中,ref 不受 React 的状态管理(State)机制控制。也就是说当 ref 的内容发生变更的时候不会触发重新渲染。

React 状态管理和渲染机制

React 的核心是响应式渲染,即当组件的状态(state)或属性(props)发生变化时,React 会重新渲染组件。这是 React 的工作原理:通过 stateprops 的变化驱动 UI 的更新。

  • 当调用 setState 时,React 会比较新旧状态,决定是否需要重新渲染组件。

  • props 的变化也会触发组件的重新渲染。

这意味着任何通过 stateprops 来管理的数据都是与 UI 渲染相关联的,React 会根据这些数据的变化决定重新渲染哪些部分。

除了 statepropsReact Context 也可以用于管理组件树中深层嵌套组件间的共享状态。Context 允许在不显式传递 props 的情况下,在父组件和子组件之间传递数据。当 Context 的值发生变化时,所有订阅该 Context 的组件都会重新渲染。因此,像 stateprops 一样,Context 也是影响组件重新渲染的关键因素。

useRef 的设计目标

useRef 的设计目标是提供一种访问 DOM 或保存组件实例的引用,而不是参与到 React 的状态管理中。它的主要作用可以分为两个方面:

  • 保存对 DOM 元素或组件实例的引用:这是 ref 最常见的用途,用于访问原生 DOM 元素或组件实例,而无需通过 React 的虚拟 DOM 进行间接操作。

  • 保存跨渲染周期的变量:useRef 还可以用来存储组件内的某些数据,但这些数据的变化不会触发组件重新渲染。

为什么 useRef 不受 React 管理?

useRef 的值是持久化的,不会触发渲染

useRef 的特殊之处在于它的 .current 属性可以在组件的整个生命周期内保持稳定。当你更新 ref.current 值时,React 并不会重新渲染组件。原因如下:

  • useRef 返回的引用对象在每次渲染时都是同一个。这意味着即使组件重新渲染,useRef 的值不会被重置。

  • useRef.current 属性的修改不会触发 React 的重新渲染,因为 React 将其视为与 UI 渲染无关的数据。

避免不必要的重新渲染

React 的重新渲染机制是基于状态变化的。如果某些数据的变化与组件的 UI 不相关,那让这些数据进入 React 的状态管理系统是没有必要的。

  • useRef 的作用正是为了存储那些不影响 UI 的数据,比如某些计时器、缓存值、滚动位置等。如果将这些数据放入 state 中,每次数据变化都会触发重新渲染,影响性能。而使用 useRef,可以避免这些不必要的重新渲染。

useRef 的生命周期

useRef 在组件的整个生命周期中是持续的。当你在一次渲染中设置了 ref.current 的值,之后的所有渲染都会保持这个值。而且,useRef 的值在组件重新渲染时也不会重置(除非组件完全卸载)。这是 useRefstate 的一个显著区别:

  • state 每次变化都会导致重新渲染。
  • useRef 的值不会随渲染变化,即便更新了 ref.current,React 也不会触发重新渲染。

useRef 的使用场景与 state 不同

通常,你会使用 state 来管理那些需要触发 UI 更新的数据,比如表单输入的值、用户操作引发的状态变化等。而 useRef 则用于存储不需要触发重新渲染的变量,比如:

  • 存储组件实例或 DOM 元素的引用。
  • 存储计数器、定时器 ID 或其他跨渲染的值。
  • 保存上一次渲染的一些状态以供对比(例如保存上一次的 props 值)。

示例代码:useRef 不触发渲染

import React, { useState, useRef } from "react";

function MyComponent() {
  const [count, setCount] = useState(0); // 触发渲染
  const refValue = useRef(0); // 不触发渲染

  const handleClick = () => {
    setCount(count + 1); // 更新 state,触发渲染
    refValue.current += 1; // 更新 ref,不触发渲染
    console.log("refValue current:", refValue.current); // 控制台输出变化,但 UI 不更新
  };

  return (
    <div>
      <p>State count: {count}</p>
      <p>Ref value: {refValue.current}</p>
      <button onClick={handleClick}>点击我</button>
    </div>
  );
}

export default MyComponent;

在上面的代码中,每次点击按钮时,state 会触发组件重新渲染,ref 的值会更新但不会导致渲染。所以你会看到 state 的值更新并反映在 UI 上,而 ref 的变化只体现在控制台输出中。

总结

  • useRef 不受 React 状态管理的原因是它的设计目标是用于存储那些不需要触发渲染的数据。

  • 它的变化不会引发组件重新渲染,因为 useRef 的主要目的是跨渲染周期保持某些引用(如 DOM 元素或普通变量),而这些引用的变化与 React 的 UI 更新机制无关。

最后分享两个我的两个开源项目,它们分别是:

这两个项目都会一直维护的,如果你想参与或者交流学习,可以加我微信 yunmz777 如果你也喜欢,欢迎 star 🚗🚗🚗