React 18中hook函数详解之useRef

在上一篇文章《React 18中hook函数详解之useState和useEffect》介绍了react v16.8版本以后,引入的Hooks函数的一些概念,以及useState和useEffect的一些用法。本文将接着上一篇文章着重介绍Hook函数当中常用的另一个函数:useRef。

useRef 是一个 React Hook,它能帮助引用一个不需要渲染的值。

useRef 返回一个只有一个属性的对象:

  • current:初始值为传递的 initialValue。之后可以将其设置为其他值。如果将 ref 对象作为一个 JSX 节点的 ref 属性传递给 React,React 将为它设置 current 属性。

在后续的渲染中,useRef 将返回同一个对象。

一、获取dom元素

最简单的用法,在函数组件中,可以基于useRef获取DOM元素

javascript 复制代码
function App() {
  const [num, setNum] = useState(0);
  const btnBox = useRef(null); 

  useEffect(() => {
    console.log(btnBox.current);
  }, [num]);

  return (
    <div>
      <span>{num}</span>
      <button ref={btnBox} onClick={() => setNum(num + 1)}>
        按钮
      </button>
    </div>
  );
}

在父子组件当中,可以使用useRef在父组件当中获取子组件的实例,进而调用子组件的方法。获取子组件的方法,就要用到另一个hook函数------useImperativeHandle。useImperativeHandle是获取函数子组件内部状态或者方法的hook。

定义一个父组件app.tsx:

javascript 复制代码
import React, { useRef, useEffect } from 'react';
import ChildName from './components/Child';
const parentRef= () => {
  const domRef = useRef<any>(null);
  const childRef = useRef<any>(null);
  useEffect(() => {
    console.log('ref:deom-init', domRef, domRef.current);
    console.log('ref:child-init', childRef, childRef.current);
  });
  const showChild = () => {
    console.log('ref:child', childRef, childRef.current);
    if (childRef.current) {
      childRef.current.say();
    }
  };
  return (
    <>
      <div style={{ margin: '100px', border: '2px dashed', padding: '20px' }}>
        <h2>这是外层组件</h2>
        <div
          onClick={() => {
            console.log('ref:deom', domRef, domRef.current);
            domRef.current.focus();
            domRef.current.value = 'hh';
          }}
          aria-hidden="true">
          <span>这是一个dom节点</span>
          <input ref={domRef} />
        </div>
        <br />
        <button onClick={showChild} style={{ marginTop: '20px' }} aria-hidden="true">
          调用子组件的函数
        </button>
        <div style={{ border: '1px solid', padding: '10px' }}>
          <ChildName ref={childRef} />
        </div>
      </div>
    </>
  );
};

export default parentRef;

二、父组件知识点

  1. useRef是一个方法,且useRef返回一个可变的ref对象;
  2. initialValue被赋值给其返回值的.current对象;
  3. 可以保存任何类型的值:dom、对象等任何可变值;
  4. ref对象与自建一个{current:''}对象的区别是:useRef会在每次渲染时返回同一个ref对象,即返回的ref对象在组件的整个生命周期内保持不变。自建对象每次渲染时都建立一个新的。
  5. ref对象的值发生改变之后,不会触发组件重新渲染。有一个窍门,把它的改变动作放到useState()之前;
  6. 本质上,useRef就是一个其.current属性保存着一个可变值"盒子"。目前我用到的是pageRef和sortRef分别用来保存分页信息和排序信息;

定义一个子组件Child.tsx:

javascript 复制代码
import React, { useImperativeHandle, forwardRef } from 'react';

const ChildName = (_props: any, ref: React.Ref<unknown> | undefined) => {
  useImperativeHandle(ref, () => ({
    say: sayHello
  }));
  const sayHello = () => {
    alert('hello,我是子组件');
  };
  return <h3>子组件</h3>;
};

export default forwardRef(ChildName);

三、子组件知识点

  1. useImperativeHandle(ref,createHandle,[deps])可以自定义暴露给父组件的实例值。如果不使用,父组件的ref(chidlRef)访问不到任何值(childRef.current==null);
  2. useImperativeHandle应该与forwradRef搭配使用;
  3. React.forwardRef会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中;
  4. React.forward接受渲染函数作为参数,React将使用prop和ref作为参数来调用此函数;
相关推荐
0和1的舞者1 小时前
Spring AOP详解(一)
java·开发语言·前端·spring·aop·面向切面
web小白成长日记1 小时前
在Vue样式中使用JavaScript 变量(CSS 变量注入)
前端·javascript·css·vue.js
QT 小鲜肉1 小时前
【Linux命令大全】001.文件管理之which命令(实操篇)
linux·运维·服务器·前端·chrome·笔记
C_心欲无痕2 小时前
react - useImperativeHandle让子组件“暴露方法”给父组件调用
前端·javascript·react.js
BullSmall4 小时前
支持离线配置修改及删除操作的实现方案
前端
全栈前端老曹4 小时前
【前端路由】Vue Router 嵌套路由 - 配置父子级路由、命名视图、动态路径匹配
前端·javascript·vue.js·node.js·ecmascript·vue-router·前端路由
EndingCoder4 小时前
安装和设置 TypeScript 开发环境
前端·javascript·typescript
张雨zy5 小时前
Vue 项目管理数据时,Cookie、Pinia 和 LocalStorage 三种常见的工具的选择
前端·javascript·vue.js
五月君_5 小时前
Nuxt UI v4.3 发布:原生 AI 富文本编辑器来了,Vue 生态又添一员猛将!
前端·javascript·vue.js·人工智能·ui
!执行5 小时前
遇到 Git 提示大文件无法上传确实让人头疼
前端·github