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 方法来达到效果。
相关推荐
小墨宝16 分钟前
js 生成pdf 并上传文件
前端·javascript·pdf
HED31 分钟前
用扣子快速手撸人生中第一个AI智能应用!
前端·人工智能
DN金猿36 分钟前
使用npm install或cnpm install报错解决
前端·npm·node.js
丘山子36 分钟前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
志存高远661 小时前
Kotlin 的 suspend 关键字
前端
www_pp_1 小时前
# 构建词汇表:自然语言处理中的关键步骤
前端·javascript·自然语言处理·easyui
YuShiYue1 小时前
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
javascript·vue.js·typescript·pnpm
天天扭码2 小时前
总所周知,JavaScript中有很多函数定义方式,如何“因地制宜”?(ˉ﹃ˉ)
前端·javascript·面试
一个专注写代码的程序媛2 小时前
为什么vue的key值,不用index?
前端·javascript·vue.js
vvilkim2 小时前
React 与 Vue:两大前端框架的深度对比
vue.js·react.js·前端框架