React+TypeScript父子组件通讯

通过本文的阅读,读者将学会如何在 React 中通过高级特性来协同父子组件间的交互。具体来说,将掌握如何利用 forwardRefuseImperativeHandle 钩子在子组件中暴露多个 DOM 节点或方法给父组件。还将了解如何在TS类型安全的前提下,准确地传递和使用这些方法和节点。文章进一步介绍了如何从子组件调用父组件中的方法,以实现组件间的逻辑交互和协作。通过这些技能,读者能够实现更加精细的组件控制和事件处理,提升 React 应用的可维护性和用户体验。

子组件将 DOM 节点暴露给父组件

在子组件中使用 forwardRef 将组件包裹,将允许组件使用 ref 将 DOM 节点暴露给父组件。

子组件:

tsx 复制代码
import {forwardRef} from "react";

// 子组件的Props类型
interface ChildrenProps {
  title: string;
}

export const Children = forwardRef<HTMLInputElement, ChildrenProps>((props, ref) => {
  return (
    <div>
      <div>{props.title}</div>
      <div><input type="text" ref={ref}/></div>
    </div>
  );
});

forwardRef 泛型中接收两个参数:

  • 第一个参数是 ref 的类型,上述示例中由于 ref 绑定到了 input 元素节点上,所以类型为 HTMLInputElement
  • 第二个参数是 props 的类型,上述示例中我们接收 title

父组件:

在父组件中调用之前我们创建好的子组件,即可传递 titleref 属性了

tsx 复制代码
import {Children} from "@/pages/Demo/Children.tsx";
import {useEffect, useRef} from "react";

export const Parent = () => {
  const childrenRef = useRef<HTMLInputElement>(null);

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

  return (
    <div className={'container-background'}>
      <Children title='辰火流光' ref={childrenRef}/>
    </div>
  );
};

在浏览器中预览:

配合 useImperativeHandle

useImperativeHandleReact Hook 之一。使用 useImperativeHandle,可以让子组件内部显式地指定通过 ref 暴露给父组件的值。

useImperativeHandle 通常和 forwardRef 一起使用,以允许函数组件接收 ref 属性。

使用场景:

  1. 当我们需要向父组件暴露子组件的某些特定方法时,而不是整个 DOM 节点或组件实例。
  2. 当我们希望能够控制父组件对子组件 ref 的访问模式,包括隐藏一些内部状态或不希望暴露的方法。

假设子组件中有两个input需要在暴露给外部

子组件代码:

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

// 子组件的Props类型
interface ChildrenProps {
  title: string;
}

// 子组件暴露给父组件调用的方法的类型
export interface ChildrenRefs {
  inputRef1: React.RefObject<HTMLInputElement>;
  inputRef2: React.RefObject<HTMLInputElement>;
}

export const Children = forwardRef<ChildrenRefs, ChildrenProps>((props, ref) => {
  // 创建多个ref
  const inputRef1 = useRef<HTMLInputElement>(null);
  const inputRef2 = useRef<HTMLInputElement>(null);

  // 使用useImperativeHandle暴露给父组件的接口
  useImperativeHandle(ref, () => ({
    // 暴露这些input的ref
    inputRef1,
    inputRef2,
  }));

  return (
    <div>
      <div>{props.title}</div>
      <div><input type="text" placeholder='input1' ref={inputRef1}/></div>
      <div><input type="text" placeholder='input2' ref={inputRef2}/></div>
    </div>
  );
});

父组件代码:

tsx 复制代码
import {Children, ChildrenRefs} from "@/pages/Demo/Children.tsx";
import {useEffect, useRef} from "react";

export const Parent = () => {
  const childrenRef = useRef<ChildrenRefs>(null);

  useEffect(() => {
    console.log(childrenRef.current?.inputRef1.current)
    console.log(childrenRef.current?.inputRef2.current)
  }, []);

  return (
    <div className={'container-background'}>
      <Children title='辰火流光' ref={childrenRef}/>
    </div>
  );
};

假设我们不想暴露出整个 <input> DOM 节点,只想要其中 focus 方法,只需要修改 useImperativeHandle 返回你想要父组件去调用的方法:

tsx 复制代码
useImperativeHandle(ref, () => ({
    inputRef1Focus(){
      inputRef1.current?.focus()
    },
    inputRef2,
}));

父组件修改以下代码:

tsx 复制代码
useEffect(() => {
    console.log(childrenRef.current?.inputRef1Focus())
    console.log(childrenRef.current?.inputRef2.current)
}, []);

子组件调用父组件的方法

只需要在父组件中传递该方法到子组件中即可

父组件:

tsx 复制代码
import {Children} from "@/pages/Demo/Children.tsx";

export const Parent = () => {
  // 父组件的方法
  const parentMethod = () => {
    console.log('父组件方法被调用')
  }

  return (
    <div className={'container-background'}>
      {/*增加传递父组件的方法*/}
      <Children onParentMethod={parentMethod} />
    </div>
  );
};

子组件:

tsx 复制代码
// 子组件的Props类型
interface ChildrenProps {
  onParentMethod: () => void;
}

export const Children = (props: ChildrenProps) => {

  const handleButtonClick=()=>{
    props.onParentMethod();
  }

  return <button onClick={handleButtonClick}>调用父组件的方法</button>
};

总结

本文介绍了如何在 React 中处理父子组件间的交互,具体包括如何通过 forwardRefuseImperativeHandle 在子组件中暴露 DOM 节点或特定方法给父组件,并增强了类型安全性。同时,我们也深入探讨了如何在子组件中调用父组件的方法,以便实现复杂的逻辑交互。

对于新手来说,理解父子组件间的交互可能稍有复杂,但一旦掌握,你会发现 React 在组件间的复用和逻辑控制方面的强大之处。实践中,这些特性能大大提高代码的可读性,可维护性甚至可测试性。

希望通过本文的学习,你已经足够熟练掌握了这些内容,能够在自己的项目中流畅地使用和掌握这些知识,构建出更加健壮且易于维护的 React 应用,提升团队的开发效率和代码质量。总的来说,理解并掌握这些特性是每一个 React 开发者的必备知识点和技能,希望本文能为你的学习之路提供帮助。

相关推荐
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
云深时现月1 小时前
jenkins使用cli发行uni-app到h5
前端·uni-app·jenkins
昨天今天明天好多天1 小时前
【Node.js]
前端·node.js
2401_857610031 小时前
深入探索React合成事件(SyntheticEvent):跨浏览器的事件处理利器
前端·javascript·react.js
雾散声声慢2 小时前
前端开发中怎么把链接转为二维码并展示?
前端
熊的猫2 小时前
DOM 规范 — MutationObserver 接口
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
天农学子2 小时前
Easyui ComboBox 数据加载完成之后过滤数据
前端·javascript·easyui
mez_Blog2 小时前
Vue之插槽(slot)
前端·javascript·vue.js·前端框架·插槽
爱睡D小猪2 小时前
vue文本高亮处理
前端·javascript·vue.js
开心工作室_kaic2 小时前
ssm102“魅力”繁峙宣传网站的设计与实现+vue(论文+源码)_kaic
前端·javascript·vue.js