使用React.forwardRef传递泛型参数

 更新时间:2023年05月12日 09:32:51   作者:Joey_Tribiani  
这篇文章主要介绍了使用React.forwardRef传递泛型参数方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

React.forwardRef传递泛型参数

使用React函数组件开发的过程中会遇到父组件调用子组件的方法或者属性的场景,首次先说怎么通过React.forwardRef来将子组件的属性或者方法暴露给父组件

使用forwardRef暴露组建的方法和属性

子组件

import { Box, Typography } from "@mui/material";
import { forwardRef, useImperativeHandle } from "react";
interface LocationChildProps {
  data: string;
}
export interface LocationChildRef {
  sayType(): void;
}
const LocationChild = forwardRef<LocationChildRef, LocationChildProps>((props, ref) => {
  useImperativeHandle(ref, () => ({
    sayType() {
      console.log("子组件的data是 " + typeof props.data);
    },
  }));
  return (
    <Box>
      <Typography>{typeof props.data}</Typography>
    </Box>
  );
});
export default LocationChild;

在子组件中我们需要接受一个key为data的props,然后在子组件中展示这个值,并且通过useImperativeHandle向外暴露一个sayType的方法, 最后用forwardRef将子组件封装然后暴露出去,这里forwardRef的作用就是包装该组件为一个可以通过Ref访问的组件。

父组件

import { Button } from "@mui/material";
import { useRef } from "react";
import ConfigDetailContainer from "../options/ConfigDetailContainer";
import LocationChild, { LocationChildRef } from "./LocationChild";
export default function DeviceLocation() {
  const locationChildRef = useRef<LocationChildRef>();
  const handleClick = () => {
    locationChildRef.current.sayType()
    // 输出: 子组件的type是 string  
  };
  return (
    <ConfigDetailContainer title="device.configTabs.LOCATION_HISTORY">
      <LocationChild ref={locationChildRef} data="asdafaf"></LocationChild>
      <Button onClick={handleClick}>查看子组件的type的类型</Button>
    </ConfigDetailContainer>
  );
}

父组件中需要通过useRef来创建ref并传递给子组件,这样父子组件就建立了连接,父组件可以通过ref来访问子组件中自定义暴露的属性或方法。

这里的操作就是父组件点击按钮控制台打印子组件接收到的data这个prop的类型。

泛型参数

现在新的问题就是我们的父组件传递的data的类型不是固定的,这时候子组件就要将data的类型用泛型来定义,所以这里就有了fowardRef传递泛型参数的问题:

我们可以这样改造子组件,思路就是将这个组件改为工厂hansh的生成模式:

import { Box, Typography } from "@mui/material";
import { forwardRef, useImperativeHandle } from "react";
export interface LocationChildProps<T = string> {
  data: T;
}
export interface LocationChildRef {
  sayType(): void;
}
const LocationChild = function <T>() {
  return forwardRef<LocationChildRef, LocationChildProps<T>>((props, ref) => {
    useImperativeHandle(ref, () => ({
      sayType() {
        console.log("子组件的data是 " + typeof props.data);
      },
    }));
    return (
      <Box>
        <Typography>{typeof props.data}</Typography>
      </Box>
    );
  });
};
export default LocationChild;

然后在父组件中使用

import { Button } from "@mui/material";
import { PropsWithRef, useRef } from "react";
import ConfigDetailContainer from "../options/ConfigDetailContainer";
import LocationChild, { LocationChildProps, LocationChildRef } from "./LocationChild";
export default function DeviceLocation() {
  const locationChildRefString = useRef<LocationChildRef>();
  const locationChildRefBoolean = useRef<LocationChildRef>();
  const handleClick = () => {
    locationChildRefString.current.sayType();
    locationChildRefBoolean.current.sayType();
  };
  const LocationChildComponent = LocationChild<string>();
  const createComponent = function <T>(props: PropsWithRef<any>, ref: React.MutableRefObject<LocationChildRef>) {
    const Mycomponent = LocationChild<T>();
    return <Mycomponent ref={ref} {...props}></Mycomponent>;
  };
  return (
    <ConfigDetailContainer title="device.configTabs.LOCATION_HISTORY">
      <LocationChildComponent ref={locationChildRefString} data={"123"}></LocationChildComponent>
      {createComponent({ data: true }, locationChildRefBoolean)}
      <Button onClick={handleClick}>查看子组件的type的类型</Button>
    </ConfigDetailContainer>
  );
}

我们可以直接调用LocationChild方法生成组件,也可以再度封装为createComponent这样的方法,这样就实现了forwardRef中使用泛型参数的需求。

react forwardRef 导致 泛型丢失

网上没有找到合适的方案,看了 antd 的源码

实现方式如下

const ForwardTable = React.forwardRef(InternalTable) as <RecordType extends object = any>(
  props: React.PropsWithChildren<TableProps<RecordType>> & { ref?: React.Ref<HTMLDivElement> },
) => React.ReactElement;
// so u can use
<Table<{id: string, b: number}>  />

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • react中hook介绍以及使用教程

    react中hook介绍以及使用教程

    这篇文章主要给大家介绍了关于react中hook及使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • JavaScript的React Web库的理念剖析及基础上手指南

    JavaScript的React Web库的理念剖析及基础上手指南

    这篇文章主要介绍了JavaScript的React Web库的理念剖析及基础上手指南,React Web的目的即是把本地的React Native应用程序项目变为Web应用程序,需要的朋友可以参考下
    2016-05-05
  • React技巧之中断map循环的方法详解

    React技巧之中断map循环的方法详解

    这篇文章主要和大家来分享一下React的技巧之如何中断map循环,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-06-06
  • React精髓!一篇全概括小结(急速)

    React精髓!一篇全概括小结(急速)

    这篇文章主要介绍了React精髓!一篇全概括小结(急速),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • React Native 截屏组件的示例代码

    React Native 截屏组件的示例代码

    本篇文章主要介绍了React Native 截屏组件的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • React函数式组件与类组件的不同你知道吗

    React函数式组件与类组件的不同你知道吗

    这篇文章主要为大家详细介绍了React函数式组件与类组件的不同,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • React通过父组件传递类名给子组件的实现方法

    React通过父组件传递类名给子组件的实现方法

    React 是一个用于构建用户界面的 JAVASCRIPT 库。这篇文章主要介绍了React通过父组件传递类名给子组件的方法,需要的朋友可以参考下
    2017-11-11
  • 基于React-Dropzone开发上传组件功能(实例演示)

    基于React-Dropzone开发上传组件功能(实例演示)

    这篇文章主要介绍了基于React-Dropzone开发上传组件,主要讲述的是在React-Flask框架上开发上传组件的技巧,需要的朋友可以参考下
    2021-08-08
  • React-Native之定时器Timer的实现代码

    React-Native之定时器Timer的实现代码

    本篇文章主要介绍了React-Native之定时器Timer的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • 浅谈react 16.8版本新特性以及对react开发的影响

    浅谈react 16.8版本新特性以及对react开发的影响

    本文主要介绍了react 16.8版本新特性以及对react开发的影响,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03

最新评论