第八章 React Hooks之useImperativeHandle、forwardRef 父子组件通信

一、专栏介绍 👏👏

欢迎加入本专栏!本专栏将引领您快速上手React,让我们一起放弃放弃的念头,开始学习之旅吧!我们将从搭建React项目开始,逐步深入讲解最核心的hooks,以及React路由、请求、组件封装以及UI(Ant Design)框架的使用。让我们一起掌握React,开启前端开发的全新篇章。

二、useImperativeHandle 📀📀

useImperativeHandle 是 React 中的一个 Hook,它能让你自定义由 ref 暴露出来的句柄。

文档中明确的说明了,默认情况下,组件不会将它们的 DOM 节点暴露给父组件。举例来说,如果你想要 MyInput 的父组件 能访问到 <input> DOM 节点,你必须选择使用 forwardRef:

所以这里我们需要先了解forwardRef

三、forwardRef 💾💾

forwardRef 允许组件使用 ref 将 DOM 节点暴露给父组件。使用 forwardRef() 让组件接收 ref 并将其传递给子组件。

TypeScript 复制代码
import { forwardRef } from 'react';

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

四、两者集合以后的案例 📷📷

4.1、子组件 👇👇

子组件的源码接收三个参数:placeholder占位符、onchange事件以及ref属性。其中,ref属性是由父组件传递给子组件的,与子组件内部的inputRef无关。通过使用这个ref属性,我们可以将子组件中的事件暴露给父组件。

TypeScript 复制代码
import React, { FC, forwardRef, useImperativeHandle, useRef } from 'react';

export type ChildType = {
  focus: () => void;
  getInputValue: () => Promise<any>;
};

const UseImperativeHandleChildDemo: FC<{
  placeholder?: string;
  onchange: (value: string) => void;
  ref: React.Ref<ChildType>;
}> = forwardRef(({ placeholder, onchange }, ref) => {
  // 这里是定义该组件内的input框的ref属性,和上面的ref有点不一样的是,上面的ref是由父组件传进来,获取子组件(本组件)内部的方法。
  const inputRef: React.MutableRefObject<HTMLInputElement | null> = useRef(null);

  useImperativeHandle(
    ref,
    () => {
      const focus = () => {
        return inputRef.current?.focus?.();
      };

      const getInputValue = () => {
        return new Promise<any>((resolve, reject) => {
          if (inputRef.current?.value) {
            resolve(inputRef.current?.value);
          } else {
            reject('您没有输入任何值');
          }
        });
      };

      return { focus, getInputValue };
    },
    []
  );

  return (
    <input placeholder={placeholder} ref={inputRef} onChange={(e) => onchange(e.target.value)} />
  );
});
export default UseImperativeHandleChildDemo;

4.2、父组件 👇👇

父组件中使用到了一个ChildType类型是由上面的子组件暴露出来的,定义这个类型是让我们更方便的获取到子组件通过ref暴露出来的方法有那些。

TypeScript 复制代码
import React, { useRef } from 'react';
import UseImperativeHandleChildDemo, { ChildType } from './UseImperativeHandleChildDemo';

function UseImperativeHandleDemo() {
  const inputRef = useRef<ChildType>(null);

  // 通过传递给子组件的ref实现子组件input框聚焦
  const handleClick = () => {
    inputRef.current?.focus();
  };

  const getInputValue = () => {
    inputRef.current
      ?.getInputValue()
      .then((value) => {
        console.log('👉👉👉-----------------点击按钮获取到的值', value);
      })
      .catch((e) => {
        console.log('👉👉👉-----------------', e);
      });
  };

  return (
    <div className="App">
      <UseImperativeHandleChildDemo
        placeholder="请输入值"
        ref={inputRef}
        onchange={(value) => {
          console.log('👉👉👉-----------------chang事件', value);
        }}
      />
      <button onClick={handleClick}>子组件input框聚焦</button>
      <button onClick={getInputValue}>获取子组件input的值</button>
    </div>
  );
}

export default UseImperativeHandleDemo;

4.3、使用组件 👇👇

通过执行这些代码以后,在浏览器控制台你就能观察到相应的信息

TypeScript 复制代码
import React from 'react';
import UseImperativeHandleDemo from './Demo/UseImperativeHandleDemo';

function App() {
  return (
    <div className="App">
      <UseImperativeHandleDemo />
    </div>
  );
}

export default App;

五、总结 💪💪

useImperativeHandle和forwardRef都是React Hooks的一部分,它们的作用和重要性如下:

useImperativeHandle是一个用于暴露自定义ref属性和自定义方法的钩子函数。它使得父组件可以通过ref访问子组件中定义的方法和属性,从而实现对子组件的精细控制。也就是说,父组件可以使用子组件的方法或者控制子组件。当使用useImperativeHandle时,需要子组件中的第二个参数(ref)当作useImperativeHandle的第一个参数。

forwardRef是一个高阶组件,用于将引用(ref)从父组件转发到子组件。这对于访问子组件的DOM元素非常有用。在父组件中,可以通过使用forwardRef来触发子组件的功能。

总的来说,useImperativeHandle和forwardRef都是React中非常重要的钩子和函数,它们可以帮助开发者更好地控制组件的行为和属性,提高代码的可读性和可维护性。

👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇 👇

相关推荐
秃头佛爷几秒前
Python学习大纲总结及注意事项
开发语言·python·学习
待磨的钝刨1 分钟前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
Devil枫3 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
A charmer4 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
尚梦4 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app