ReactHooks:useRef使用场景

1. 使用 ref 引用一个值

const intervalRef = useRef(initialValue);

useRef 返回一个具有单个 current 属性的 ref 对象。current 属性值可以修改,初始值为 initialValue。与 state 不同的是,改变 ref 不会触发重新渲染,因此可以使用 useRef 存储那些在组件多次渲染之间需要存储但又不需要渲染在页面上的数据,如定时器 ID、缓存的请求结果等。

js 复制代码
import { useRef } from "react";

export default () => {
  const count = useRef(0);

  const handleClick = () => {
    count.current += 1;
    console.log(count.current);
  };

  return (
    <>
      <span>count: {count.current} </span>
      <button onClick={handleClick}>点击增加</button>
    </>
  );
};


使用 useRef 实现倒计时,可用于发送验证码

js 复制代码
import { useRef, useState } from "react";

export default () => {
  const [count, setCount] = useState(undefined);
  const intervalId = useRef(null);

  const handleStart = () => {
    setCount(5);
    intervalId.current = setInterval(() => {
      setCount((count) => {
        if (count === 0) {
          clearInterval(intervalId.current);
          return undefined;
        }
        return count - 1;
      });
    }, 1000);
  };

  return (
    <>
      <button onClick={handleStart}>
        {count ? "倒计时:" + count : "发送验证码"}
      </button>
    </>
  );
};

2. 通过 ref 操作 DOM

useRef 可以关联到组件的 DOM 元素上,通过 ref.current 来访问该 DOM 元素,以便直接访问元素的方法或属性,如获取焦点、获取滚动位置等。

js 复制代码
import { useRef } from 'react';

export default () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  }

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

3. 访问其他组件的 DOM 节点或方法

默认情况下,react 不允许访问其他组件的 DOM 节点,即使是自己的子组件。需要使用 forwardRef API 将父组件的 ref 转发给子组件,从而使父组件可以操作子组件的 DOM。

js 复制代码
import { useRef, forwardRef } from 'react';

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

export default () => {
  const ref = useRef(null);

  const handleClick = () => {
    ref.current.focus();
  }

  return (
    <>
      <MyInput ref={ref} />
      <button onClick={handleClick}>
        聚焦输入框
      </button>
    </>
  );
}

useImperativeHandle 通常和 forwardRef 一起使用,用于向父组件暴露一个自定义的 ref 句柄。通常用于需要在父组件中调用子组件中定义的函数的情况。

js 复制代码
import { useRef, forwardRef, useImperativeHandle } from "react";

const MyInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  const handleFocus = () => {
    inputRef.current.focus();
  };

  // useImperativeHandle 返回一个对象,包含了父组件可以通过 ref 访问到的属性和方法
  useImperativeHandle(ref, () => ({
    handleFocus,
  }));
  
  // useImperativeHandle(ref, () => {
  //   return { handleFocus };
  // });
  
  return <input {...props} ref={inputRef} />;
});

export default () => {
  const ref = useRef(null);

  const handleClick = () => {
    ref.current.handleFocus();
  };

  return (
    <>
      <MyInput ref={ref} />
      <button onClick={handleClick}>聚焦输入框</button>
    </>
  );
};

上面两段代码都实现了聚焦输入框的功能,区别在于:

  • 单独使用 forwardRef 时,父组件可以通过 ref 直接访问到子组件的 DOM 节点,而无法访问到子组件的属性或方法。在第一个例子中,子组件渲染了一个 input 元素,并通过 forwardRef 将父组件创建的 ref 传递给这个元素,从而可以在父组件中通过 ref.current 来调用 input 这个 DOM 元素上的方法 focus。
  • 结合使用 forwardRef 和 useImperativeHandle 时,可以自定义父组件通过 ref 访问到的子组件的方法。这就意味者你可以暴露子组件内部自定义的函数给父组件,而不仅仅是 DOM 节点。在第二个例子中,父组件并没有直接操作子组件的 DOM 元素,而是通过 ref 来调用子组件暴露给父组件的 handleFocus 方法来达到效果。
相关推荐
永乐春秋23 分钟前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿24 分钟前
【前端】CSS
前端·css
ggdpzhk26 分钟前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
小曲曲1 小时前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
学不会•3 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS3 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜5 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点5 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow5 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o5 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app