问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

React中useRef钩子的使用技巧

创作时间:
作者:
@小白创作中心

React中useRef钩子的使用技巧

引用
1
来源
1.
https://developer.aliyun.com/article/1629174

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

基础概念

什么是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,并在实际开发中避免常见的问题和易错点。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号