盘点React常用Hooks(2)—— useRef | 青训营

124 阅读5分钟

React Hook

上篇文章中我们介绍了React中最常用也是最重要的两个HookuseState以及useEffect,本次的文章我们将继续介绍React中常用的另外一个Hook——useRef。同时将useRefuseState进行对比,希望可以帮助大家更好地理解并使用钩子函数。

useRef - 持久化引用

函数定义

useRef是一个较为常用的钩子函数,用于在函数组件中创建一个可以存储和访问持久性数据的引用。它主要用于在组件中存储和获取DOM节点、保存上一个状态值等持久性数据。

useRef 的用法和特点:

  • 创建引用: 你可以使用 useRef 创建一个引用,并将其初始化为 null 或其他初始值。
  • 持久性数据存储: useRef 创建的引用可以在组件的整个生命周期中保持不变。每次组件重新渲染时,useRef 返回的引用都是相同的。
  • 不触发重新渲染: 与状态钩子不同,修改 useRef 创建的引用并不会触发组件的重新渲染。
  • 访问 DOM 节点: useRef最常见的用途之一是获取DOM元素的引用,用于执行DOM操作。

使用示例

下面是一个示例,展示了如何使用useRef来获取DOM节点的引用:

import React, { useRef, useEffect } from 'react';

function FocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // 在组件挂载后,将输入框自动聚焦
    inputRef.current.focus();
  }, []);

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>聚焦输入框</button>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>使用 useRef 示例</h1>
      <FocusInput />
    </div>
  );
}

export default App;

useref1.gif

在这个示例中,inputRef 是一个引用,使用 useRef(null) 初始化。在 useEffect 中,当组件挂载后,inputRef.current.focus() 会自动聚焦输入框。同时,通过点击按钮也可以再次聚焦输入框。

此外你也可以通过ref.current.style.xxx来修改DOM节点的样式:

import React, {useRef} from 'react';  

function App() {  
    const divRef = useRef(null);  
    
    const changeColor = () => {  
        divRef.current.style.backgroundColor = divRef.current.style.backgroundColor === 'lightblue'?'white':'lightblue'
    };  
  
    return (  
        <div>  
            <button onClick={changeColor}>改变背景颜色</button>  
            <div  
                ref={divRef}  
                style={{  
                width: '200px',  
                height: '200px',  
                }}  
            ></div>  
        </div>  
    );  
}  
  
export default App;

useref2.gif

useRef与useState的区别

上篇文章中我们谈到了useState钩子函数,和本次的useRef一样,两者都可用于在函数组件中声明和管理数据,但它们的实际用途和作用却有些不同。下面是它们之间的主要区别:

  • 触发重新渲染:

    • useState:当使用 useState 来声明状态并通过对应的更新函数修改状态时,React 会自动识别状态变化,并重新渲染组件,以反映状态的变化。
    • useRefuseRef 创建的引用变化不会触发组件的重新渲染,因为它主要用于存储数据和获取 DOM 节点引用,而不是用于触发渲染。
  • 数据持久性:

    • useState:状态变量是可变的,会随着组件的重新渲染而重新初始化,不具备持久性。
    • useRef:引用变量是持久的,不会随着组件的重新渲染而重新初始化,可以用来存储需要在多次渲染之间保持一致的数据。

综上所述,useState 主要用于状态管理和触发组件的重新渲染,而useRef主要用于获取持久性的引用和操作 DOM,不触发组件的重新渲染。

在绝大多数情况下,推荐使用 useState 来管理组件的状态,这样可以更好地利用React的状态管理机制,保持代码的可维护性和可预测性。如果需要直接操作DOM,可以在特定情况下使用 useRef,但要小心绕过了React的控制,可能会导致代码难以追踪和维护。

渲染机制

上面讲到了useStateuseRef函数一个很大的区别就在于是否会触发组件的重新渲染。但如果只是修改DOM节点的样式,我们并不能分辨出两者的区别。下面我们将通过使用useEffect钩子函数来感受两者的区别。

使用useState:

import React, {useEffect, useState} from 'react';  
  
function App() {  
  
  // 组件初始化的过程中会执行一次useEffect
  // 在组件每次渲染完成后也会执行一次
    useEffect(() => {  
        console.log('Component re-rendered');  
    });  

    const [isBlue, setIsBlue] = useState(true);  

    const toggleColor = () => {  
        setIsBlue(!isBlue);  
    };  

    return (  
        <div>  
            <button onClick={toggleColor}>切换颜色</button>  
            <div  
                style={{  
                width: '200px',  
                height: '200px',  
                backgroundColor: isBlue ? 'lightblue' : 'white'  
                }}  
            ></div>  
        </div>  
    );  
}  
  
export default App;

浏览器响应效果及控制台展示:

useref3.gif

使用useRef:

import React, {useEffect, useRef} from 'react';  
  
// App 组件  
function App() {  

    // 组件初始化的过程中会执行一次useEffect
    // 在组件每次渲染完成后也会执行一次
    useEffect(() => {  
    console.log('Component re-rendered');  
    });  

    const divRef = useRef(null);  

    const changeColor = () => {  
        divRef.current.style.backgroundColor = divRef.current.style.backgroundColor === 'lightblue'?'white':'lightblue'  
    };  

    return (  
        <div>  
            <button onClick={changeColor}>改变背景颜色</button>  
            <div  
                ref={divRef}  
                style={{  
                width: '200px',  
                height: '200px',  
                backgroundColor: 'lightblue',
                }}  
            ></div>  
        </div>  
    );  
}  
  
export default App;

浏览器响应效果及控制台展示:

useref4.gif

通过对比可以看出,使用useRef钩子函数对DOM样式进行修改不会触发组件的重新渲染,而每一次调用useState修改状态都会触发组件的重新渲染。

总结

通过本次的学习,相信大家对useRef钩子函数的定义与使用都有了一定的了解。此外,通过对比我们也可以更加明确不同钩子函数的使用场景。由于过多地使用 useState 可能会导致频繁的组件重新渲染,从而影响性能。所以在遇到需要操作DOM的业务场景时,我们经常可以使用useRef快速解决问题。同时我们也需要利用useRef的特性帮助我们存储持久性数据以及维护引用的稳定性。

[第一篇](盘点React常用Hooks(1)—— useState、useEffect | 青训营 - 掘金 (juejin.cn))