react+ts实现 父子组件通信

创建ts+react的命令

npx create-react-app react-ts --template typescript

使用React和TypeScript进行开发与使用JavaScript进行开发在逻辑上是相同的,但TypeScript增加了类型安全性,这在大型应用中可以减少错误,提高代码的可维护性。下面我将分别用JavaScript和TypeScript演示父子组件的通信。

具体实现

JS实现父子组件的通信

父组件传递数据给子组件

ParentComponent.js

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [parentData, setParentData] = useState('Data from Parent');

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent data={parentData} />
    </div>
  );
}

export default ParentComponent;

ChildComponent.js

import React from 'react';

function ChildComponent(props) {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{props.data}</p>
    </div>
  );
}

export default ChildComponent;
子组件传递数据给父组件

ParentComponent.js

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [childData, setChildData] = useState('');

  const handleChildData = (data) => {
    setChildData(data);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent onData={handleChildData} />
      <p>Data from Child: {childData}</p>
    </div>
  );
}

export default ParentComponent;

ChildComponent.js

import React from 'react';

function ChildComponent(props) {
  const sendDataToParent = () => {
    props.onData('Data from Child');
  };

  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={sendDataToParent}>Send Data to Parent</button>
    </div>
  );
}

export default ChildComponent;

TypeScript实现父子组件的通信

1. 父组件传递数据给子组件

ParentComponent.tsx

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [parentData, setParentData] = useState<string>('Data from Parent');

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent data={parentData} />
    </div>
  );
}

export default ParentComponent;

ChildComponent.tsx

import React from 'react';

interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;
ts 相关知识介绍

在TypeScript中,接口(Interface)和类型别名(Type Alias)都是用来定义对象结构的方式,但它们之间有一些关键的区别。下面我将为你详细介绍这两种定义方式,并解释如何在React组件中使用它们来声明Props的类型。

接口(Interface)

接口在TypeScript中是一种定义对象结构的方式,它通常用于定义对象的“形状”(shape)。接口可以包含属性、方法、索引签名等,但不能包含具体的实现。使用接口可以确保某个对象符合特定的结构。

示例:

interface Person {
  name: string;
  age: number;
  greet: () => void;
}

const user: Person = {
  name: "Alice",
  age: 30,
  greet: () => console.log(`Hello, my name is ${this.name}`),
};

在这个例子中,Person 接口定义了一个具有 nameagegreet 方法的对象结构。user 对象实现了这个接口。

类型别名(Type Alias)

类型别名是另一种定义对象结构的方式,但它更加灵活。类型别名可以用来描述基本类型、联合类型、元组、字面量类型等,并且可以包含更复杂的类型定义,如交叉类型、条件类型等。

示例:

type Person = {
  name: string;
  age: number;
};

type GreetingFunction = () => void;

type User = Person & { greet: GreetingFunction };

const user: User = {
  name: "Bob",
  age: 25,
  greet: () => console.log(`Hello, my name is ${user.name}`),
};

在这个例子中,User 类型别名使用了交叉类型,结合了 Person 对象和 greet 方法。

在React组件中声明Props类型

在React组件中,你可以使用接口或类型别名来定义组件的Props类型,以确保组件接收到的Props符合预期的结构。

使用接口:

interface MyComponentProps {
  title: string;
  count: number;
}

const MyComponent: React.FC<MyComponentProps> = ({ title, count }) => (
  <div>{title} - {count}</div>
);

使用类型别名:

type MyComponentProps = {
  title: string;
  count: number;
};

const MyComponent: React.FC<MyComponentProps> = ({ title, count }) => (
  <div>{title} - {count}</div>
);

在这两个示例中,MyComponent 组件都使用了 React.FC(Functional Component)来定义,并且通过泛型参数指定了Props的类型。这样,当组件的Props不符合定义的类型时,TypeScript编译器会给出错误提示。

总的来说,接口和类型别名都是TypeScript中定义类型的强大工具,选择使用哪一个取决于你的具体需求和个人偏好。接口更适合用于定义对象的结构,而类型别名提供了更多的灵活性和复杂类型的定义能力。在React组件中,使用它们可以提高代码的可维护性和可读性。

React.FC<MyComponentProps>

React.FC 是TypeScript中的泛型语法。结合了React的函数组件类型 React.FC(Functional Component的缩写)。

这段代码中使用的 React.FC<MyComponentProps> 是TypeScript中的泛型语法,结合了React的函数组件类型 React.FC(Functional Component的缩写)。让我来详细解释一下这个语法:

函数组件类型(React.FC)

在React中,函数组件是一个返回React元素的函数。React 16.8及以上版本引入了Hooks,使得函数组件可以包含状态和副作用。React.FC 是React TypeScript定义中用于类型化函数组件的泛型类型。

泛型(Generics)

泛型是TypeScript的一个特性,它允许你定义函数、类、接口或类型别名,这些可以接收一个或多个类型参数,然后在定义中使用这些类型参数来创建一个可重用的组件,这个组件可以用于多种不同的类型。

React.FC

当你看到 React.FC<MyComponentProps> 这样的写法时,实际上是在告诉TypeScript编译器:

  • React.FC 是一个泛型类型,它需要一个类型参数来指定组件的Props类型。
  • <MyComponentProps> 是传递给 React.FC 的类型参数,它是一个接口,定义了组件的Props结构。

这样,MyComponent 组件就被类型化为一个函数组件,它的Props必须符合 MyComponentProps 接口中定义的结构。如果传递给组件的Props不符合这个结构,TypeScript编译器将会给出错误。

示例解释

在你提供的代码示例中:

interface MyComponentProps {
  title: string;
  count: number;
}

const MyComponent: React.FC<MyComponentProps> = ({ title, count }) => (
  <div>{title} - {count}</div>
);
  • MyComponentProps 接口定义了组件的Props,包括一个 title 属性(类型为 string)和一个 count 属性(类型为 number)。
  • MyComponent 组件使用 React.FC<MyComponentProps> 来声明它的类型,这意味着它是一个函数组件,其Props类型由 MyComponentProps 接口定义。
  • 当你调用 MyComponent 组件并传递Props时,这些Props需要符合 MyComponentProps 接口的结构,否则TypeScript编译器会报错。

这种写法的好处是提高了代码的类型安全性和可维护性,因为TypeScript编译器会在编译时检查Props的类型,帮助开发者避免运行时错误。


2. 子组件传递数据给父组件

ParentComponent.tsx

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [childData, setChildData] = useState<string>('');

  const handleChildData = (data: string) => { // 可以直接将set函数作为回调函数传递给子组件,而不需要额外封装一个函数
    setChildData(data);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent onData={handleChildData} />
      <p>Data from Child: {childData}</p>
    </div>
  );
}

export default ParentComponent;

ChildComponent.tsx

import React from 'react';

interface ChildComponentProps {
  onData: (data: string) => void;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ onData }) => {
  const sendDataToParent = () => { // 可以直接调用onData函数,不用再封装一次
    onData('Data from Child');
  };

  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={sendDataToParent}>Send Data to Parent</button>
    </div>
  );
};

export default ChildComponent;
区别总结
  1. 类型声明

    • 在JavaScript中,没有类型声明,所有类型都是隐式的。
    • 在TypeScript中,使用接口(interface)或者类型别名(type)来定义Props的类型,并在组件中明确声明这些类型。
  2. 代码的安全性

    • TypeScript通过静态类型检查,在编译时捕捉类型错误,增强了代码的安全性和可维护性。
    • JavaScript没有静态类型检查,类型错误只能在运行时发现。
  3. 开发体验

    • 使用TypeScript,IDE(如VSCode)会提供更好的代码补全、类型提示和重构支持。

通过这两种实现方式的对比,你可以看到TypeScript在类型安全性和代码可维护性方面的优势,尤其是对于大型项目,这些优势会更加明显。

完整代码

Father.tsx

import { useState } from "react";
import Son from "./Son";
const Father = () => {
   // 注意这里和js不同,要加<number>,当然,并不是必须的,删了也没有报错
   // <number> 是TypeScript的泛型语法,表示我们希望 useState 管理的状态变量的类型是 number
  const [fatherMoney, setFatherMoney] = useState<number>(100);
  return (
    <div style={{ border: "blue 1px solid" }}>
      <p>这里是父亲组件,fatherMoney:{fatherMoney}</p>
      <Son data={fatherMoney} changeFatherMoney={setFatherMoney}></Son>
      // 这里可以直接把set函数传递过去,不用在封装一个函数
    </div>
  );
};

export default Father;

Son.tsx

import React from "react";

interface SonProps {
  data: number; // 父传子
  changeFatherMoney: (data: number) => void; // 子传父,需要在接口,里面定义类型,不然Father回报错,就是在添加onClick={() => changeFatherMoney(data - 1)}的时候
}

const Son: React.FC<SonProps> = ({ data, changeFatherMoney }) => {
  return (
    <div style={{ border: "1px red solid" }}>
      <p>这里是子组件</p>
      父亲的数据是:{data}
      // 这里可以直接传参数
      <button onClick={() => changeFatherMoney(data - 1)}>用父亲一块钱</button>
    </div>
  );
};

export default Son;

在这里插入图片描述

App.tsx

import Father from "./compoents/Father";

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

export default App;

React.FC<ChildComponentProps>解释

在TypeScript中,React.FC<ChildComponentProps> 是用于定义 React 函数组件的一种类型注解。它有助于确保组件的属性(props)符合预期的类型,并为组件的使用提供类型安全和智能提示。

详细解释

  • React.FCReact.FunctionComponent 的简写,是一个泛型接口,用于定义函数组件。
  • ChildComponentProps 是一个接口或类型别名,用于描述组件的 props 的结构和类型。

通过使用 React.FC<ChildComponentProps>,我们告诉 TypeScript 这个函数组件将接收的 props 必须符合 ChildComponentProps 接口的定义。

示例代码

定义 ChildComponentProps 接口

首先,我们定义一个接口 ChildComponentProps,描述这个组件所需要的 props 的类型:

interface ChildComponentProps {
  data: string; // props 中需要有一个字符串类型的 `data`
}
使用 React.FC<ChildComponentProps>

然后,我们定义一个函数组件 ChildComponent,并使用 React.FC<ChildComponentProps> 进行类型注解:

import React from 'react';

interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;

主要优势

  1. 类型安全

    • 确保组件接收的 props 符合预期的类型。在编写或使用组件时,如果提供的 props 类型不正确,TypeScript 会在编译时提示错误。
  2. 自动推断和提示

    • 使用 React.FC,TypeScript 会自动推断组件的返回类型为 JSX.Element,并为 props 提供智能提示和自动补全。
  3. 默认包含 children

    • React.FC 默认包含了 children 属性,这对于需要传递子元素的组件非常方便。如果不需要 children 属性,可以显式地将其从接口中移除。

包含 children 属性

import React from 'react';

interface ChildComponentProps {
  data: string;
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data, children }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
      {children}
    </div>
  );
};

export default ChildComponent;

不包含 children 属性

如果你不希望组件接受 children 属性,可以将其显式移除:

import React, { ReactNode } from 'react';

interface ChildComponentProps {
  data: string;
  children?: never; // 显式移除 `children` 属性
}

const ChildComponent: React.FC<ChildComponentProps> = ({ data }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{data}</p>
    </div>
  );
};

export default ChildComponent;

总结

通过使用 React.FC<ChildComponentProps> 进行类型注解,你可以确保组件的 props 类型安全,并享受更好的开发体验,包括智能提示和自动补全。 这种类型注解在团队合作和大型项目中尤其重要,因为它可以显著减少由于类型错误引起的 bug。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/719629.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云计算 |(五)云基础设施机制

文章目录 📚云基础设施机制🐇逻辑网络边界🐇虚拟防火墙🐇虚拟专用网络VPN🐇虚拟服务器🐇云存储设备⭐️云存储等级⭐️网络存储接口⭐️对象存储接口⭐️数据库存储接口🐇云使用监控⭐️监控代理⭐️资源代理⭐️轮询代理📚云基础设施机制 🐇逻辑网络边界 将…

“Docker之道:优雅管理容器数据的艺术“

目录 1. 容器数据卷 1.1 容器卷的概念 1.2 容器卷的使用 1.3 个人案例实现容器卷挂载 1.4 MySQL同步数据案例&#xff08;容器数据卷操作&#xff09; 1.4.1 获取 MySQL 镜像 1.4.2 运行 MySQL 容器并配置数据持久化 参数说明&#xff1a; 1.4.3 测试 MySQL 连接 1.4…

表面声波滤波器——叉指换能器(3)

叉指换能器(interdigital transducers&#xff0c;IDT) 是在压电基片表面激励和检测声表面波&#xff0c;从而实现电信号和声信号间的相互转换。 叉指换能器由在压电基片表面上沉积两组互相交错&#xff0c;周期分布的状金属条带(叉指电极)组成&#xff0c;每组电极和一个汇流…

Python Pyperclip:获取剪贴板中的值

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在日常生活和工作中&#xff0c;经常需要将一些信息从一个地方复制到另一个地方。这时&#xff0c;剪贴板就显得尤为重要了。Python作为一门强大的编程语言&#xff0c;也提供了许多方便的工具来帮助处理剪贴板中的数…

【数据结构与算法(C语言)】离散事件模拟- 单链表和队列的混合实际应用

目录 1. 前言2. 流程图3. 数据结构3.1 单链表3.2 链式队列 4. 核心函数4.1 银行业务模拟 void BankSimulation()4.2 初始化 void OpenForDay()4.3 客户到达 void CustomerArrived(Event en)4.4 客户离开 void CustomerArrived(Event en) 5. 非核心函数5.1 新建客户 NewCustomer…

eNSP学习——配置基于全局地址池的DHCP

目录 主要命令 原理概述 实验目的 实验场景 实验拓扑 实验编址 实验步骤 1、基本配置 2、配置基于全局地址池的 DHCP Server 3、配置DHCP Client 主要命令 [R1]dhcp enable //开启 DHCP功能//创建一个全局地址池&#xff0c;地址池名称为huawei1 [R1]ip pool h…

.net8 blazor auto模式很爽(三)用.net8的Blazor自动模式测试,到底在运行server还是WebAssembly

Blazor自动模式到底什么时侯在运行server&#xff0c;什么时侯在运行WebAssembly。这个对我们来说非常重要&#xff0c;官方并没有很清楚地告诉我们。并且存在一些误导&#xff0c;让我们觉得自动模式就是不管我怎么弄&#xff0c;blazor都会自动识别该使用server还是WebAssemb…

计算机网络:3数据链路层

数据链路层 概述封装成帧和透明传输帧透明传输&#xff08;填充字节或比特&#xff09;差错检测奇偶校验循环冗余校验CRC Cyclic Redundancy Check 可靠传输停止-等待协议回退n帧协议&#xff08;滑动窗口协议&#xff09;选择重传协议 点对点协议PPP共享式以太网网络适配器&am…

哪些因素驱动新零售发展?新零售与传统零售、电子商务区别在哪?

零售业正经历着一场前所未有的变革&#xff0c;这场变革由多种因素驱动&#xff0c;涉及技术、消费习惯以及商业模式的全面升级。我们称之为”新零售”&#xff0c;它不仅仅是一个概念&#xff0c;更是零售业未来发展的方向。新零售的兴起&#xff0c;标志着零售行业正在迈向一…

Survival Animations

一套生存游戏的动画集,包括采集、建造、捕鱼、剥皮/鞣制、篝火等更多内容。 总动画数:89 建造/制作 30 篝火 28 饮水 3 水壶 3 觅食 2 治疗 3 空闲 1 原始捕鱼 7 剥皮 1 矛捕鱼 4 伐木 5 下载:​​Unity资源商店链接资源下载链接 效果图:

Ubuntu22.04之比较工具:Bcompare与Meld显示空格与tab(二百五十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Java基础学习-方法

目录 方法基础概念 方法的格式&#xff1a; 案例&#xff1a;最简单方法的定义 案例&#xff1a;带参数的方法调用 案例&#xff1a;求圆的面积 带有返回值的方法&#xff1a; 方法注意点 方法的重载&#xff1a; ​编辑 案例&#xff1a;数组的遍历&#xff1a; 案例…

Apache Doris 之 Docker 部署篇

前言 在现代数据驱动的商业环境中&#xff0c;实时数据分析和高并发查询能力是企业成功的关键因素之一。传统的数据仓库和分析工具在面对大规模数据处理和实时分析需求时&#xff0c;往往力不从心。Apache Doris 作为一个现代的 MPP 数据库管理系统&#xff0c;凭借其强大的查…

MySQL 数据库 Navicat Premium 16.01 安装教程

MySQL 数据库 Navicat Premium 16.01 安装教程 目录 MySQL 数据库 Navicat Premium 16.01 安装教程前言安装步骤同意协议选择安装目录桌面快捷方式安装正在安装安装完成 步骤获取 前言 MySQL数据库管理用Navicat更加方便&#xff0c;可视化效果更好&#xff0c;今天给大家带来…

Thermo Fisher赛默飞TSQ单杆电源维修1R120380-0001

美国热电质朴分析仪电路板维修&#xff0c;液相色谱质谱联用仪维修&#xff0c;Thermo Fisher赛默飞世尔光谱仪IS10 IS5赛默飞主板维修。 公司仪器维修设备备有三相交流电源,变频电源&#xff0c;无油空压气源&#xff0c;标准化的维修平台、电子负载&#xff0c;耐压测试仪、老…

Python实现管线建模 - 3.同心变径管

往期回顾 Python实现管线建模 || 1.圆直管、方管https://blog.csdn.net/Xxy9426/article/details/138836778?spm1001.2014.3001.5501 对依赖库的补充 随着后续内容的深入&#xff0c;我发现单纯靠trimesh库已经无法完成后续的建模&#xff08;涉及到多个几何体拼接或者是创建…

采购芯片时细心,再细心!

检查原理图&#xff0c;采购时候的细心对照所费的时远远少于焊完找BUG的时间&#xff01;&#xff01;&#xff01; 购买芯片的时候不光看芯片名称&#xff0c;封装&#xff0c;丝印也要看&#xff0c;如果不一样必须对照两者的引脚图仔细观察是否一样&#xff01;&#xff01…

边缘检测(一)-灰度图像边缘检测方法

灰度图像边缘检测是数字图像处理与机器视觉中经常遇到的一个问题&#xff0c;边缘检测是否连续、光滑是判断检测方法优劣的一个重要标准&#xff0c;下面通过一个实例提供灰度图像边缘检测方法&#xff0c;该方法对其他图像检测也具有一定的参考价值。 首先&#xff0c;读入一幅…

国际期货常见技术面分析

技术分析方法&#xff1a;通过对市场行为本身的分析来预测价格的变动方向&#xff0c;及主要是对期货市场的日常交易状况&#xff0c;包括价格、交易量与持仓量等数据&#xff0c;按照时间顺序绘制成图形、图表/形成一定的指标系统。然而针对这些图形、图表/指标系统进行分析研…

【C++】类和对象的引入

文章目录 前言一、类的定义二、类的访问控制与封装三、类的作用域四、类的实例化五、类的存储方式及大小计算六、隐藏的this指针 前言 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&…