文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用React.forwardRef传递泛型参数

2023-05-20 05:20

关注

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}>  />

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯