useRef 钩子使用技巧

举报
超梦 发表于 2024/10/24 08:35:53 2024/10/24
【摘要】 在 React 中,useRef 是一个非常有用的 Hook,它可以让你在组件的生命周期内保留一些数据,而不会引起组件的重新渲染。本文将从基础概念入手,逐步深入到 useRef 的常见问题、易错点及如何避免这些问题,并通过代码示例来帮助理解其应用场景和实现方式。 基础概念 什么是 useRef?useRef 是一个 React Hook,它返回一个可变的 ref 对象,其 .current ...

在 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 提供了 useState 和 useReducer 来管理状态,而 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,并在实际开发中避免常见的问题和易错点。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。