当前位置: 首页 > news >正文

React 组件的通信方式

在 React 应用开发中,组件之间的通信是构建复杂用户界面和交互逻辑的关键。正确地实现组件通信能够让我们的应用更加灵活和易于维护。以下是几种常见的 React组件通信方式。

一、父子组件通信

1. 通过 props 传递数据(父组件向子组件传递数据)

  • 原理:
    在 React 中,props 是一种从父组件向子组件传递数据的机制。父组件在渲染子组件时,可以将数据作为属性传递给子组件。子组件通过接收 props 来获取父组件传递的数据,并在自身的渲染过程中使用这些数据。这种方式遵循了单向数据流的原则,即数据从父组件流向子组件,使得数据的流动清晰可追踪。
  • 示例代码:
// 父组件
import React from 'react';
import ChildComponent from './ChildComponent';function ParentComponent() {const userName = 'John Doe';const userAge = 30;return (<div><ChildComponent name={userName} age={userAge} /></div>);
}export default ParentComponent;// 子组件
import React from 'react';function ChildComponent(props) {return (<div><p>Name: {props.name}</p><p>Age: {props.age}</p></div>);
}export default ChildComponent;

2. 父组件通过回调函数接收子组件传递的数据(子组件向父组件通信)

  • 原理:
    当子组件需要向父组件传递数据时,父组件可以向子组件传递一个回调函数作为 props。子组件在特定的事件触发时(如按钮点击、表单提交等)调用这个回调函数,并将需要传递的数据作为参数传递给该回调函数。这样父组件就能接收到子组件传来的数据,实现反向的数据流动。
  • 示例代码:
// 父组件
import React from 'react';
import ChildComponent from './ChildComponent';function ParentComponent() {const handleChildMessage = (message) => {console.log('Received message from child:', message);};return (<div><ChildComponent onMessage={handleChildMessage} /></div>);
}export default ParentComponent;// 子组件
import React from 'react';function ChildComponent(props) {const sendMessage = () => {const message = 'Hello from child!';props.onMessage(message);};return (<button onClick={sendMessage}>Send Message</button>);
}export default ChildComponent;

二、兄弟组件通信

1. 利用共同父组件实现通信

  • 通过共同父组件中转数据:
    当两个兄弟组件需要通信时,可以通过它们的共同父组件来实现。一个兄弟组件通过父组件传递的回调函数向父组件传递数据,父组件再将数据通过 props 传递给另一个兄弟组件。本质是父子之间通信
  • 示例代码:
// 父组件
import React from 'react';
import SiblingA from './SiblingA';
import SiblingB from './SiblingB';function ParentComponent() {const [message, setMessage] = React.useState('');const handleMessageFromA = (msg) => {setMessage(msg);};return (<div><SiblingA onSendMessage={handleMessageFromA} /><SiblingB message={message} /></div>);
}export default ParentComponent;// 兄弟组件 A
import React from 'react';function SiblingA(props) {const sendMessage = () => {const msg = 'Hello from Sibling A';props.onSendMessage(msg);};return (<button onClick={sendMessage}>Send Message to Sibling B</button>);
}export default SiblingA;// 兄弟组件 B
import React from 'react';function SiblingB(props) {return (<div>{props.message}</div>);
}export default SiblingB;

三、跨级组件通信

1. 使用 React Context API

  • 原理:
    React Context 提供了一种在组件树中跨多个层级共享数据的方法,无需通过一级一级地传递 props。它允许我们创建一个上下文(Context),在这个上下文中的组件都可以访问到共享的数据。当数据在顶层的 Context.Provider 中更新时,所有订阅了该 Context 的组件都会收到通知并重新渲染。
  • 示例代码:

Context允许我们在组件树中传递数据,而不必手动通过Props一层层传递

创建:

  • 使用 React.createContext() 创建上下文对象
  • 并在组件中使用 Provider 组件的value属性提供数据
  • 子组件通过 Consumer 或 useContext 获取数据。
// 创建 Context
import React from 'react';const ThemeContext = React.createContext();// 顶层组件(提供数据)
function App() {const theme = {color: 'blue',backgroundColor: 'lightblue'};return (<ThemeContext.Provider value={theme}><Header /></ThemeContext.Provider>);
}// 中间组件(无需关心 Context 数据)
function Header() {return (<div><Navigation /></div>);
}// 底层组件(使用 Context 数据)
function Navigation() {return (<ThemeContext.Consumer>{theme => (<ul style={theme}><li>Home</li><li>About</li><li>Contact</li></ul>)}</ThemeContext.Consumer>);
}

在函数式组件中,更常用的是 useContext 钩子来获取 Context 中的数据,示例如下:

import React, { useContext } from 'react';const ThemeContext = React.createContext();function App() {const theme = {color: 'blue',backgroundColor: 'lightblue'};return (<ThemeContext.Provider value={theme}><Header /></ThemeContext.Provider>);
}function Header() {return (<div><Navigation /></div>);
}function Navigation() {const theme = useContext(ThemeContext);return (<ul style={theme}><li>Home</li><li>About</li><li>Contact</li></ul>);
}

这样,无论组件嵌套层级有多深,都可以通过 Context API 方便地实现跨层级组件通信。

四、非父子关系组件通信(发布订阅模式)

1. 使用Event Bus进行通信

对于一些非父子关系且较为松散的组件通信场景,可以使用发布订阅模式。在 React 中,可以借助第三方库如 mitt 来实现。

首先安装 mitt 库:npm install mitt

例如,有组件 ComponentA 和 ComponentB,它们之间没有直接的父子或兄弟关系。在一个单独的事件总线文件 eventBus.js 中:

import mitt from'mitt';const emitter = mitt();export default emitter;

在 ComponentA 中,当某个事件发生时发布消息:

import React from'react';
import emitter from './eventBus';const ComponentA = () => {const handleClick = () => {const data = "来自组件 A 的消息";emitter.emit('customEvent', data);};return (<div><button onClick={handleClick}>触发事件</button></div>);
};export default ComponentA;

在 ComponentB 中,订阅该事件并接收数据:

import React, { useEffect } from'react';
import emitter from './eventBus';const ComponentB = () => {useEffect(() => {const subscription = emitter.on('customEvent', (data) => {console.log(`收到组件 A 消息: ${data}`);});return () => {// 组件卸载时取消订阅subscription();};}, []);return (<div><p>组件 B 等待接收消息</p></div>);
};export default ComponentB;

五、使用 Redux 等状态管理库

  • 原理:
    Redux 是一个可预测的状态容器,用于管理 JavaScript 应用中的状态。在 React 应用中结合 Redux,我们可以将数据存储在一个单一的 store 中。组件可以通过 dispatch 动作(action)来触发状态的改变,而通过订阅 store 的变化,组件可以获取到最新的状态。这种方式适合于大型应用中复杂的跨级组件通信场景,使得状态的管理更加集中和可维护。
  • 示例代码(简化版) :
    首先,安装 redux 和 react-redux 库。
// 定义 action 类型
const SET_USER_INFO = 'SET_USER_INFO';// action 创建函数
const setUserInfoAction = (userInfo) => ({type: SET_USER_INFO,payload: userInfo
});// reducer 函数
const initialState = {user: null
};
const rootReducer = (state = initialState, action) => {switch (action.type) {case SET_USER_INFO:return {...state, user: action.payload };default:return state;}
};// 创建 store
import { createStore } from 'redux';
const store = createStore(rootReducer);// 在顶层组件中 dispatch 动作
import React from 'react';
import { Provider } from 'react-redux';
import ChildComponent from './ChildComponent';function App() {const handleSetUserInfo = () => {const userInfo = { name: 'Alice', age: 25 };store.dispatch(setUserInfoAction(userInfo));};return (<Provider store={store}><button onClick={handleSetUserInfo}>Set User Info</button><ChildComponent /></Provider>);
}// 在子组件中获取 store 中的数据
import React from 'react';
import { useSelector } from 'react-redux';function ChildComponent() {const user = useSelector(state => state.user);return (<div>{user && (<p>User Name: {user.name}, Age: {user.age}</p>)}</div>);
}

相关文章:

React 组件的通信方式

在 React 应用开发中&#xff0c;组件之间的通信是构建复杂用户界面和交互逻辑的关键。正确地实现组件通信能够让我们的应用更加灵活和易于维护。以下是几种常见的 React组件通信方式。 一、父子组件通信 1. 通过 props 传递数据&#xff08;父组件向子组件传递数据&#xff0…...

WAV文件双轨PCM格式详细说明及C语言解析示例

WAV文件双轨PCM格式详细说明及C语言解析示例 一、WAV文件双轨PCM格式详细说明1. WAV文件基本结构2. PCM编码方式3. 双轨PCM格式详细说明二、C语言解析WAV文件的代码示例代码说明一、WAV文件双轨PCM格式详细说明 WAV文件是一种用于存储未压缩音频数据的文件格式,广泛应用于音频…...

【ES6复习笔记】数值扩展(16)

介绍 在 JavaScript 中&#xff0c;数值扩展提供了一些额外的功能&#xff0c;使得处理数值变得更加方便。本教程将介绍一些常用的数值扩展方法和属性。 1. Number.EPSILON Number.EPSILON 是 JavaScript 表示的最小精度。它的值接近于 2.2204460492503130808472633361816E-…...

百度热力图数据日期如何选择

目录 1、看日历2、看天气 根据研究内容定&#xff0c;一般如果研究城市活力的话&#xff0c;通常会写“非重大节假日&#xff0c;非重大活动&#xff0c;非极端天气等”。南方晴天不多&#xff0c;有小雨或者中雨都可认为没有影响&#xff0c;要不然在南方很难找到完全一周没有…...

Vue.js 高级组件开发:设计模式与实践

Vue.js 高级组件开发&#xff1a;设计模式与实践 引言一、组合式 API 与动态依赖注入1. 基于 provide/inject 的动态依赖2. 动态依赖注入与懒加载 二、动态渲染与自定义渲染函数1. 使用 Render 函数动态生成内容2. 自定义 vnode 操作 三、复杂场景下的动态表单生成与验证四、高…...

《一文读懂卷积网络CNN:原理、模型与应用全解析》

《一文读懂卷积网络CNN&#xff1a;原理、模型与应用全解析》 一、CNN 基本原理大揭秘&#xff08;一&#xff09;从人类视觉到 CNN 灵感&#xff08;二&#xff09;核心组件详解 二、经典 CNN 模型巡礼&#xff08;一&#xff09;LeNet-5&#xff1a;开山鼻祖&#xff08;二&a…...

MONI后台管理系统-数据敏感字段存储加密

前言&#xff1a;     在我们数据库中&#xff0c;存在很多的敏感数据&#xff0c;如用户表中&#xff0c;存在用户电话、身份证号、邮箱等属于用户的敏感信息&#xff0c;我们通常在存入数据库后&#xff0c;将其进行加密存储&#xff0c;以此来保证数据安全性。     …...

熟悉各类游戏设计模式的用途与限制,如 factory、strategy、mvc、object pool 等

良好的系统分析与设计能力要求开发者熟悉并正确运用各种设计模式来解决特定问题。设计模式是一种针对特定问题的通用解决方案&#xff0c;可提高代码的可复用性、可维护性和可扩展性。以下是对一些常见游戏设计模式的详细分析&#xff0c;包括其用途、限制和代码示例。 一、工厂…...

【RabbitMQ高级篇】消息可靠性问题(1)

目录 1.消息可靠性 1.1.生产者消息确认 1.1.1.修改配置 1.1.2.定义Return回调 1.1.3.定义ConfirmCallback 1.2.消息持久化 1.2.1.交换机持久化 1.2.2.队列持久化 1.2.3.消息持久化 1.3.消费者消息确认 1.3.1.演示none模式 1.3.2.演示auto模式 1.4.消费失败重试机制…...

ASP.NET |日常开发中常见问题归纳讲解

ASP.NET &#xff5c;日常开发中常见问题归纳讲解 前言一、性能问题1.1 数据库访问性能1.2 视图状态&#xff08;在ASP.NET Web Forms 中&#xff09; 二、安全问题2.1 SQL 注入2.2 跨站脚本攻击&#xff08;XSS&#xff09; 三、状态管理问题3.1 会话状态&#xff08;Session …...

【【深入浅出TinyRisc-v】】

深入浅出TinyRisc-v 本代码参考于 https://gitee.com/liangkangnan/tinyriscv 自己理解之后又重新写了一遍 tinyriscv.v // 涓嬮潰鏄鏁翠釜top妯″潡鐨勪功鍐? module tinyriscv(input clk ,input rst_n …...

常见的限流算法

常见的限流算法 限流的定义固定窗口算法滑动窗口算法漏桶算法&#xff08;推荐&#xff09;令牌桶算法(推荐)限流粒度本地限流&#xff08;单机限流&#xff09;分布式限流&#xff08;多机限流&#xff09;分布式限流的实现 限流的定义 限流&#xff0c;也称流量控制。是指系统…...

【Leetcode 每日一题】3159. 查询数组中元素的出现位置

问题背景 给你一个整数数组 n u m s nums nums&#xff0c;一个整数数组 q u e r i e s queries queries 和一个整数 x x x。 对于每个查询 q u e r i e s [ i ] queries[i] queries[i]&#xff0c;你需要找到 n u m s nums nums 中第 q u e r i e s [ i ] queries[i] q…...

xadmin后台首页增加一个导入数据按钮

xadmin后台首页增加一个导入数据按钮 效果 流程 1、在添加小组件中添加一个html页面 2、写入html代码 3、在urls.py添加导入数据路由 4、在views.py中添加响应函数html代码 <!DOCTYPE html> <html lang...

行为树详解(5)——事件驱动

【分析】 如果行为树的节点很多&#xff0c;那么会存在要经过很多节点才会走到动作节点的情况。显然&#xff0c;性能上不如状态机。 每帧都需要重新遍历一系列节点才会走到动作节点&#xff0c;而实际上很多条件节点在数帧内不会有变化&#xff0c;这是造成性能问题的重要原…...

3.若依前端项目拉取、部署、访问

因为默认RuoYi-Vue是使用的Vue2,所以需要另外去下载vue3来部署。 拉取代码 git clone https://gitee.com/ys-gitee/RuoYi-Vue3.git 安装node才能执行npm相关的命令 执行命令npm install 如果npm install比较慢的话&#xff0c;需要添加上国内镜像 npm install --registrhttp…...

Debian操作系统相对于Ubuntu有什么优势吗?

更高的稳定性&#xff1a;Debian 以其出色的稳定性闻名&#xff0c;得益于严格的软件包测试和发布流程。其稳定版经过长时间测试与验证&#xff0c;确保了系统的高度稳定&#xff0c;更适合对稳定性要求极高的长期运行服务器环境。而 Ubuntu 虽有稳定版本&#xff0c;但更新周期…...

【漏洞复现】CVE-2015-3337 Arbitrary File Reading

漏洞信息 NVD - CVE-2015-3337 Directory traversal vulnerability in Elasticsearch before 1.4.5 and 1.5.x before 1.5.2, when a site plugin is enabled, allows remote attackers to read arbitrary files via unspecified vectors. 在安装了具有“site”功能的插件以…...

win10、win11-鼠标右键还原、暂停更新

系统优化 win 10jihuo win 11jihuo鼠标右键还原暂停更新 update 2024.12.28win 10 jihuo winx&#xff0c;打开powershell管理员&#xff0c;输入以下命令,选择1并等待 irm https://get.activated.win | iex参考&#xff1a;https://www.bilibili.com/video/BV1TN411M72J/?sp…...

FFmpeg来从HTTP拉取流并实时推流到RTMP服务器

当使用FFmpeg来从HTTP拉取流并实时推流到RTMP服务器时&#xff0c;你可以使用以下命令&#xff1a; ffmpeg -i http://输入流地址 -c:v copy -c:a copy -f flv rtmp://RTMP服务器地址/应用名称/流名称 这是一个基本的命令示例&#xff0c;其中&#xff1a; - -i http://输入流地…...

深入解析AUTOSAR通信模块:从信号抽象到多路CAN配置

1. AUTOSAR通信模块的核心价值 第一次接触AUTOSAR通信模块时&#xff0c;我被它复杂的层级关系绕得头晕。直到在实车上调试快充CAN信号时&#xff0c;才真正理解这种架构设计的精妙之处。简单来说&#xff0c;AUTOSAR的Com模块就像个智能邮局&#xff0c;负责把应用层产生的各种…...

基于ABB RobotStudio的工业机器人课程学习(第一周)

本周内容——成功安装并试用ABB RobotSyudioABB RobotStudio 6.08 安装教程 ABB RobotStudio作为工业机器人离线编程与仿真的核心工具&#xff0c;是开展工业机器人工作站设计、轨迹仿真的重要平台&#xff0c;其中6.08版本兼具稳定性与实用性&#xff0c;适配工业机器人仿真教…...

内存取证新手必看:用Lovelymem+MemProcFS挂载分析,像访问文件夹一样查看RAW镜像

内存取证革命&#xff1a;用LovelymemMemProcFS实现零命令行分析 想象一下&#xff0c;当你拿到一个18GB的内存镜像文件时&#xff0c;不再需要面对密密麻麻的命令行参数和漫长的等待时间。传统内存取证工具如Volatility虽然强大&#xff0c;但对于初学者来说&#xff0c;记忆各…...

TVBoxOSC:电视盒子全能播放解决方案终极指南

TVBoxOSC&#xff1a;电视盒子全能播放解决方案终极指南 【免费下载链接】TVBoxOSC TVBoxOSC - 一个基于第三方项目的代码库&#xff0c;用于电视盒子的控制和管理。 项目地址: https://gitcode.com/GitHub_Trending/tv/TVBoxOSC 你是否曾经为电视盒子播放视频时遇到格式…...

别再踩坑了!KubeKey离线安装K8s v1.26.12时,containerd镜像拉取失败的完整避坑指南

KubeKey离线部署K8s集群&#xff1a;containerd镜像拉取全流程避坑手册 第一次用KubeKey离线部署Kubernetes集群时&#xff0c;containerd镜像拉取失败的问题让我折腾了大半天。看着部署日志里反复出现的证书错误提示&#xff0c;才意识到离线环境下的镜像仓库配置远比想象中复…...

Matlab/Simulink仿真BLDC电机:避开转速闭环控制的5个常见坑

BLDC电机转速闭环仿真避坑指南&#xff1a;从参数配置到结果验证的完整解决方案 在电机控制领域&#xff0c;BLDC&#xff08;无刷直流电机&#xff09;因其高效率、长寿命和低维护成本等优势&#xff0c;已成为工业自动化、电动汽车和消费电子等领域的主流选择。Matlab/Simul…...

PROJECT MOGFACE自动化运维:服务器监控日志分析与告警报告生成

PROJECT MOGFACE自动化运维&#xff1a;服务器监控日志分析与告警报告生成 每天凌晨&#xff0c;当运维工程师小李被手机告警铃声惊醒&#xff0c;睡眼惺忪地打开电脑&#xff0c;面对几十台服务器海量的监控图表和日志文件时&#xff0c;他总在想&#xff1a;有没有一种方法&…...

迷宫问题求解:从递归到队列的算法实战与性能对比

1. 迷宫问题与三种经典解法 迷宫问题就像我们小时候玩的走迷宫游戏&#xff0c;需要在错综复杂的路径中找到一条从起点到终点的通路。在计算机科学中&#xff0c;迷宫被抽象成一个二维矩阵&#xff0c;其中0代表可通行的路径&#xff0c;1代表障碍物。这个问题看似简单&#xf…...

AD快捷键避坑指南:为什么你的自定义快捷键总是不生效?

AD快捷键避坑指南&#xff1a;为什么你的自定义快捷键总是不生效&#xff1f; 在AD&#xff08;Altium Designer&#xff09;这个功能强大的电子设计自动化软件中&#xff0c;快捷键是提升工作效率的利器。但很多用户都遇到过这样的困扰&#xff1a;明明按照教程设置了自定义快…...

FireRedASR Pro在微信小程序开发中的应用:实时语音输入与转写

FireRedASR Pro在微信小程序开发中的应用&#xff1a;实时语音输入与转写 不知道你有没有这样的经历&#xff1a;用手机打字回复长消息时&#xff0c;手指按得发酸&#xff1b;或者在线听课时&#xff0c;想快速记下老师的重点&#xff0c;手速却跟不上语速。在移动优先的今天…...