useRef 钩子使用技巧

本文涉及的产品
可观测可视化 Grafana 版,10个用户账号 1个月
可观测监控 Prometheus 版,每月50GB免费额度
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 【10月更文挑战第12天】本文详细介绍了 React 中的 `useRef` Hook,包括其基础概念、基本用法、常见问题与易错点以及如何避免这些问题。通过具体代码示例,解释了 `useRef` 的应用场景,如保存对 DOM 元素的引用、保存回调函数和定时器 ID 等,帮助开发者更有效地使用这一工具。

在 React 中,useRef 是一个非常有用的 Hook,它可以让你在组件的生命周期内保留一些数据,而不会引起组件的重新渲染。本文将从基础概念入手,逐步深入到 useRef 的常见问题、易错点及如何避免这些问题,并通过代码示例来帮助理解其应用场景和实现方式。
image.png

基础概念

什么是 useRef?

useRef 是一个 React Hook,它返回一个可变的 ref 对象,其 .current 属性被初始化为传递的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

基本用法

import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

export default TextInputWithFocusButton;

在这个例子中,useRef 用于获取对输入框的引用,以便在按钮点击时将其聚焦。

常见问题与易错点

1. 误用 useRef 来存储状态

useRef 不应该用来存储组件的状态。React 提供了 useStateuseReducer 来管理状态,而 useRef 主要用于保存那些不需要触发重新渲染的数据。

错误示例

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

function Counter() {
  const countRef = useRef(0);

  useEffect(() => {
    countRef.current++;
  });

  return (
    <div>
      Count: {countRef.current}
    </div>
  );
}

export default Counter;

在这个例子中,countRef 用于存储计数器的值,但由于 countRef 的变化不会触发重新渲染,因此界面上的计数器值不会更新。

正确示例

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

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  return (
    <div>
      Count: {count}
    </div>
  );
}

export default Counter;

2. 忘记初始化 ref

在使用 useRef 时,忘记初始化 ref 可能会导致 undefined 错误。

错误示例

import React, { useRef } from 'react';

function Example() {
  const myRef = useRef();

  useEffect(() => {
    console.log(myRef.current.value); // 可能会抛出错误
  }, []);

  return (
    <input ref={myRef} type="text" />
  );
}

export default Example;

正确示例

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

function Example() {
  const myRef = useRef(null);

  useEffect(() => {
    console.log(myRef.current?.value); // 使用可选链操作符
  }, []);

  return (
    <input ref={myRef} type="text" />
  );
}

3. 在函数组件中使用 ref

在函数组件中使用 ref 时,需要确保正确地传递 ref

错误示例

import React, { useRef } from 'react';

function CustomInput(props) {
  return <input {...props} />;
}

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

  return (
    <CustomInput ref={inputRef} />
  );
}

export default App;

正确示例

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

const CustomInput = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

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

  return (
    <CustomInput ref={inputRef} />
  );
}

export default App;

如何避免这些问题

  1. 明确用途useRef 用于保存那些不需要触发重新渲染的数据,不要用它来管理状态。
  2. 初始化 ref:始终初始化 ref,避免 undefined 错误。
  3. 使用可选链操作符:在访问 ref 的属性时,使用可选链操作符(?.)来防止潜在的 undefined 错误。
  4. 正确传递 ref:在自定义组件中使用 forwardRef 来正确传递 ref

进阶用法

1. 保存回调函数

useRef 可以用于保存回调函数,以避免在每次渲染时都创建新的函数引用。

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

function UseRefCallbackExample() {
  const callbackRef = useRef(null);

  useEffect(() => {
    callbackRef.current = handleScroll;
  });

  const handleScroll = () => {
    console.log('Scrolled');
  };

  useEffect(() => {
    window.addEventListener('scroll', callbackRef.current);
    return () => {
      window.removeEventListener('scroll', callbackRef.current);
    };
  }, []);

  return (
    <div>
      Scroll down to see the effect.
    </div>
  );
}

export default UseRefCallbackExample;

2. 保存定时器 ID

useRef 可以用于保存定时器 ID,以便在组件卸载时清除定时器。

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

function TimerExample() {
  const timerIdRef = useRef(null);

  useEffect(() => {
    timerIdRef.current = setInterval(() => {
      console.log('Tick');
    }, 1000);

    return () => {
      clearInterval(timerIdRef.current);
    };
  }, []);

  return (
    <div>
      Timer is running...
    </div>
  );
}

export default TimerExample;

总结

useRef 是一个非常强大的 Hook,可以帮助你在组件的生命周期内保留一些数据,而不会引起组件的重新渲染。通过本文的介绍和代码示例,希望你能更好地理解和应用 useRef,并在实际开发中避免常见的问题和易错点。

目录
相关文章
|
前端开发 JavaScript
深入理解React中的useEffect钩子函数
深入理解React中的useEffect钩子函数
109 0
|
前端开发
react hooks 使用小技巧—useState传值函数
当使用useState时,传入一个函数作为初始状态值的参数和传入一个值的参数的效果是一样的,都会在组件渲染时被调用,但它们的使用场景略有不同。
618 1
|
7月前
|
前端开发
React中useEffect、useCallBack、useLayoutEffect
React中useEffect、useCallBack、useLayoutEffect
|
14天前
|
前端开发
深入探索React Hooks:从useState到useEffect
深入探索React Hooks:从useState到useEffect
19 3
|
2月前
|
前端开发 开发者
useContext 钩子详解
【10月更文挑战第14天】`useContext` 是 React 中的一个 Hook,用于在组件树中传递数据,避免手动传递 props。本文从基本概念、使用方法、常见问题及解决方法等方面详细介绍了 `useContext`,并提供了代码示例,帮助开发者更好地理解和应用这一钩子。
51 5
|
2月前
|
前端开发 JavaScript 开发者
useEffect 钩子详解与实战
【10月更文挑战第3天】React 作为一个流行的 JavaScript 库,通过 Hooks 大幅简化了组件开发。`useEffect` 是一个核心 Hook,用于处理函数组件中的副作用操作,如数据获取和 DOM 更改。本文详细介绍了 `useEffect` 的基本语法、常见用法及示例,包括模拟 `componentDidMount`、`componentDidUpdate` 和 `componentWillUnmount`。此外,还探讨了如何避免无限循环渲染和内存泄漏等问题,并提供了相应的解决方案,帮助开发者更好地理解和应用 `useEffect`,提升应用程序的性能与稳定性。
56 7
|
5月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
96 1
|
7月前
|
前端开发 JavaScript 开发者
掌握React中的useEffect:函数组件中的魔法钩子
掌握React中的useEffect:函数组件中的魔法钩子
|
7月前
|
前端开发 JavaScript 测试技术
React Hooks之useState、useRef
React Hooks之useState、useRef
|
7月前
|
存储 前端开发 JavaScript
React Hooks的useState、useRef使用
React Hooks的useState、useRef使用
72 2