第八章 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中非常重要的钩子和函数,它们可以帮助开发者更好地控制组件的行为和属性,提高代码的可读性和可维护性。

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

相关推荐
真滴book理喻16 分钟前
Vue(四)
前端·javascript·vue.js
蜜獾云18 分钟前
npm淘宝镜像
前端·npm·node.js
dz88i818 分钟前
修改npm镜像源
前端·npm·node.js
Jiaberrr22 分钟前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook
ZSYP-S25 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos28 分钟前
c++------------------函数
开发语言·c++
程序员_三木40 分钟前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊1 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama1 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全1 小时前
Java的基础概念(一)
java·开发语言·python