多种 React 组件通信方式实践

在React中,组件之间的通信是一个非常重要的话题。当我们构建复杂的应用程序时,经常需要不同的组件之间共享数据或者进行相互协作。React提供了几种方式来实现跨组件通信,下面我将详细其中几种通信方式,并提供实际的代码示例。

使用 React Context

基于 React Context 实现跨组件通信的一个常见用例是创建一个能够在不同组件间共享和触发行为的上下文。以下是一个简化的例子,展示了如何在 app.tsx 中触发其他组件(例如,一个弹窗组件)中的方法。

1. 创建一个 Context

首先,我们创建一个新的 Context。这个 Context 将包含我们想要在应用中共享的方法。

import React, { createContext, useContext } from 'react';// 创建 Context
const MyContext = createContext({togglePopup: () => {}, // 这是一个示例方法
});

2. 创建一个 Context Provider

接下来,创建一个提供者组件,它将使得在应用的不同部分都能够访问到 Context 中的值。

export const MyProvider = ({ children }) => {const togglePopup = () => {// 这里实现弹窗的显示隐藏逻辑console.log("Toggle Popup called");};return (<MyContext.Provider value={{ togglePopup }}>{children}</MyContext.Provider>);
};

3. 在 app.tsx 中使用 Provider

在 app.tsx 中,用 MyProvider 包裹整个应用,使得任何子组件都能够访问 Context 中的值。

import React from 'react';
import { MyProvider } from './MyProvider'; // 引入刚才创建的 Providerfunction App() {return (<MyProvider>{/* 应用的其余部分 */}</MyProvider>);
}export default App;

4. 在子组件中使用 Context

最后,在需要的组件中使用这个 Context。例如,如果你有一个弹窗组件,你可以在其中使用这个 Context。

import React, { useContext } from 'react';
import { MyContext } from './MyContext';const Popup = () => {const { togglePopup } = useContext(MyContext);return (<div>{/* 弹窗的内容 */}<button onClick={togglePopup}>关闭弹窗</button></div>);
};export default Popup;

在这个例子中我们创建了一个可以在整个应用中共享的 Context。我们定义了一个 togglePopup 方法,并在需要的组件中通过 Context 使用它。这种方式使得跨组件通信变得简单和模块化。

使用自定义事件

使用自定义事件进行组件间通信是一种非常灵活的方法。在 React 中,我们可以使用第三方库,如 mitt 或 eventemitter3 来实现这一机制。下面是一个基于此思想的实现示例。以下是使用 mitt 的示例。mitt 是一个轻量级的事件发射器/监听器库。

1.安装 mitt

使用 npm install mitt 安装事件监听器,然后创建一个 Event 实例,这个实例将在整个应用中共享。

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

2.在 app.tsx 中触发事件

在 app.tsx 中,你可以触发一个自定义事件,这个事件将被其他组件监听和响应。

import React from 'react';
import emitter from './emitter';function App() {const openPopup = () => {emitter.emit('togglePopup', true);};return (<div><button onClick={openPopup}>打开弹窗</button>{/* 其他组件 */}</div>);
}export default App;

3.在其他组件中监听事件

在你的公共组件(例如一个弹窗组件)中,监听之前在 app.tsx 中触发的事件。

import React, { useEffect, useState } from 'react';
import emitter from './emitter';const Popup = () => {const [isOpen, setIsOpen] = useState(false);useEffect(() => {const toggleListener = (state) => {setIsOpen(state);};emitter.on('togglePopup', toggleListener);return () => {emitter.off('togglePopup', toggleListener);};}, []);if (!isOpen) return null;return (<div>{/* 弹窗内容 */}<button onClick={() => setIsOpen(false)}>关闭弹窗</button></div>);
};export default Popup;

这个例子展示了如何使用 mitt 来实现跨组件通信。这种方法对于那些不便于通过 props 或 state 进行传递的复杂交互特别有用。它还可以帮助你减少对全局状态管理解决方案的依赖,从而使组件保持更加解耦和可重用。

使用 React Ref

使用 React Ref 实现组件间的方法调用是一种直接且有效的方式,尤其适用于父组件需要直接调用子组件中的方法的场景。以下是一个使用 React Ref 实现的示例。

1.创建子组件并暴露方法

首先,创建一个子组件并使用 useImperativeHandle 与 forwardRef 来暴露特定的方法。

import React, { useImperativeHandle, forwardRef } from 'react';const Popup = forwardRef((props, ref) => {useImperativeHandle(ref, () => ({openPopup: () => {console.log("弹窗打开");// 弹窗打开的逻辑},closePopup: () => {console.log("弹窗关闭");// 弹窗关闭的逻辑}}));return (<div>这里是弹窗的内容</div>);
});export default Popup;

2.在父组件中使用 Ref 调用方法

接下来,在父组件中创建一个 ref,并将其传递给子组件。然后,使用这个 ref 来调用子组件中的方法。

import React, { useRef } from 'react';
import Popup from './Popup';function App() {const popupRef = useRef();const openPopup = () => {popupRef.current.openPopup();};const closePopup = () => {popupRef.current.closePopup();};return (<div><button onClick={openPopup}>打开弹窗</button><button onClick={closePopup}>关闭弹窗</button><Popup ref={popupRef} /></div>);
}export default App;

使用 React Ref 来调用子组件的方法是一个非常直观和简单的方法,特别适合于需要直接从父组件控制子组件行为的场景。它允许父组件通过 ref 直接访问子组件的实例

使用 Redux 实现组件间通信

Redux 是一种流行的状态管理库,适用于大型 React 应用。通过 Redux,你可以在应用的不同部分共享状态和逻辑。以下是一个简化的例子,展示如何使用 Redux 来更新和访问应用状态。

1.设置 Redux

首先,你需要设置 Redux 的基本元素:store、reducers 和 actions。

// actions.js
export const togglePopup = () => ({type: 'TOGGLE_POPUP'
});// reducer.js
const initialState = {isPopupOpen: false
};export const reducer = (state = initialState, action) => {switch (action.type) {case 'TOGGLE_POPUP':return { ...state, isPopupOpen: !state.isPopupOpen };default:return state;}
};// store.js
import { createStore } from 'redux';
import { reducer } from './reducer';export const store = createStore(reducer);

2.在 app.tsx 中使用 Redux

使用 Redux 的 Provider 来包裹你的应用,并在需要的地方通过 dispatch 触发 action。

import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
import { togglePopup } from './actions';
import Popup from './Popup';function App() {return (<Provider store={store}><button onClick={() => store.dispatch(togglePopup())}>切换弹窗状态</button><Popup /></Provider>);
}export default App;

3.在其他组件中连接 Redux

在需要的组件中使用 connect 函数(或 useSelector 和 useDispatch 钩子)来访问和更新 Redux 的状态。

import React from 'react';
import { connect } from 'react-redux';const Popup = ({ isPopupOpen }) => {if (!isPopupOpen) return null;return (<div>弹窗内容</div>);
};const mapStateToProps = state => ({isPopupOpen: state.isPopupOpen
});export default connect(mapStateToProps)(Popup);

Redux 提供一个集中的存储,用于管理整个应用的状态。这对于大型应用来说是非常有用的,因为它可以避免状态在多个组件之间的重复传递。Redux 通过将逻辑集中和模块化,提高了代码的维护性和扩展性。且拥有广泛的中间件和生态系统,支持异步操作、日志记录、持久化等高级功能。

使用 Callbacks 实现组件间通信

通过 props 向子组件传递回调函数是 React 中最基本的通信方式之一。

1.在父组件中定义和传递 Callback

import React, { useState } from 'react';
import Popup from './Popup';function App() {const [isPopupOpen, setIsPopupOpen] = useState(false);const togglePopup = () => {setIsPopupOpen(!isPopupOpen);};return (<div><button onClick={togglePopup}>切换弹窗状态</button><Popup isOpen={isPopupOpen} onClose={togglePopup} /></div>);
}export default App;

2.在子组件中使用 Callback

import React from 'react';const Popup = ({ isOpen, onClose }) => {if (!isOpen) return null;return (<div>弹窗内容<button onClick={onClose}>关闭</button></div>);
};export default Popup;

对于简单的父子组件通信,使用回调函数是直接且简单的,它避免了引入额外的库或复杂的架构。以保持组件的独立性和可重用性,因为子组件不需要关心状态是如何被管理的,只需关注它如何响应这些回调。

回调方法不需要任何额外的状态管理库或上下文,这使得应用更轻量,减少了依赖和引入的复杂性。对于小型或不太复杂的应用,使用回调进行状态管理通常足够,并且可以避免过度设计。

总结

在 React 中,组件通信是构建动态和交互式用户界面的关键部分。React 提供了多种方式来实现组件之间的通信,本文列举了其中的几种通信方式并提供了代码示例,每种方式都适用于不同的场景和需求。希望这篇文章能够帮助你更好地理解和运用这些技术。


看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React入门使用 (官方文档向 Part1)

文章目录 React组件:万物皆组件 JSX: 将标签引入 JavaScriptJSX 规则1. 只能返回一个根元素2. 标签必须闭合3. 使用驼峰式命名法给 ~~所有~~ 大部分属性命名&#xff01;高级提示&#xff1a;使用 JSX 转化器 在 JSX 中通过大括号使用 JavaScript使用引号传递字符串使用大括号&…

招投标信息可以用CRM系统来查看吗?

对于B2B企业来说获客难、获客成本高是共识。做大客户的企业通过招投标获取商机是一个重要获客途径&#xff0c;然而传统方式管理招投标信息问题很多&#xff0c;例如资料丢失、手工录入出错、信息分散、信息查找费时费力。为了解决这些难题小编推荐CRM系统&#xff0c;CRM系统需…

Java基础之集合类

Java基础之集合类 一、集合的框架1.1、集合概述1.2、集合与数组区别1.3、数组的缺点&#xff1a;1.4、常用集合分类1.5、Collection常用方法 二、List集合2.1、ArrayList2.2、LinkedList2.3、Vector2.4、区别 三、Set集合3.1、HashSet集合3.2、LinkedHashSet集合3.3、TreeSet集…

Qt 网络通信

获取本机网络信息 &#xff08;1&#xff09;在 .pro 文件中加入 QT network&#xff08;2&#xff09; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QLabel> #include <QLineEdit> #include <QPu…

C#中openFileDialog控件的使用方法

目录 一、OpenFileDialog基本属性 二、使用 OpenFile 从筛选的选择中打开文件 1.示例源码 2.生成效果 3. 其它示例 三、使用 StreamReader 以流的形式读取文件 1.示例源码 2.生成效果 四、一种新颖的Windows窗体应用文件设计方法 在C#中&#xff0c;OpenFileDialog控件…

vue3+tsx的使用

<template><div><xiaoman on-click"getItem" name"似懂非懂"></xiaoman></div> </template><script setup langts>import xiaoman from "./App"const getItem(item:any)>{console.log(item,it…

redis引发的一次生产事故,内存爆满

redis引发的一次生产事故 问题描述&#xff1a; 发版后回归测试&#xff0c;不定时出现token失效&#xff0c;导致自动退出到登录界面。如果操作的人员较多&#xff0c;token失效的就比较快&#xff0c;操作的人员较少token失效的相对较慢。 问题复现&#xff1a; 同一账号…

【LeeCode】*904.水果成篮

你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而&#xff0c;农场的主人设定了一些严格的规矩&#xff0c;你必须按照要求采摘水果&…

《C++PrimePlus》第10章 对象和类

10.1 过程性编程和面向对象编程 10.2 抽象和类 10.3 类的构造函数和析构函数 类的定义和使用&#xff08;买卖股票&#xff09; 头文件stock10.h #ifndef __STOCK00__H__ #define __STOCK00__H__#include <string>class Stock { // pravate的内容只能通过public访问 p…

简易地铁自动机售票系统实现(C++)

该程序具有以下功能 (1) 一个地铁路线类 Router&#xff0c;包含路线编号&#xff0c;途中的各个站点。可以新增、删除、查询路线&#xff0c;可以根据线路名称&#xff0c;显示线路图片。 (2) 一个地图类 Map&#xff0c;可以显示所有可以乘坐的地铁站名&#xff0c;以及线路…

leetcode 不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;…

MybatisBatchUtils功能介绍

MybatisBatchUtils 是一个 MyBatis 框架的工具类&#xff0c;主要用于简化 MyBatis 中批量操作的代码编写。该工具类封装了 MyBatis 中的批量操作方法&#xff0c;可以方便地进行批量插入、更新和删除等操作。 一般来说&#xff0c;使用 MyBatis 进行批量操作需要先设置 JDBC 驱…

展锐Android10,R,lmk怎么添加白名单

展锐Android10,R,lmk怎么添加白名单 低内存lmk时,怎么添加白名单 [ANSWER] 如果要保活进程,使之不被lowmemorykiller杀掉,可以将要保活的进程加到白名单中: lmkd_param.conf文件是lmkd杀进程的白名单配置文件,其中配置的应用是不会被lmkd杀掉的 请在device/sprd目录中…

js用到的算法

1.对象数组中&#xff0c;对象中有对象&#xff0c;数组根据对象中的对象打平 [{indexValueMap: { 68443: 0, 68457: 0 },rowName1: 固定收益类,rowName2: 交易类,rowName3: 次级},{indexValueMap: { 68443: 0, 68457: 0 },rowName1: 固定收益类,rowName2: 交易类,rowName3: 中…

虚幻学习笔记—点击场景3D物体的两种处理方式

一、前言 本文使用的虚幻引擎为5.3.2&#xff0c;两种方式分别为&#xff1a;点击根物体和精准点击目标物体。 二、实现 2.1、玩家控制器中勾选鼠标点击事件&#xff1a;这一步很重要&#xff0c;如图2.1.1所示&#xff1a;在自定义玩家控制器中勾 图2.1.1 选该项&#xff0c…

nacos集群开箱搭建-linux版本搭建

原创/朱季谦 nacos是一款易于构建云原生应用的动态服务发现、配置管理和服务管理平台&#xff0c;简单而言&#xff0c;它可以实现类似zookeeper做注册中心的功能&#xff0c;也就是可以在springcloud领域替代Eureka、consul等角色&#xff0c;同时&#xff0c;还可以充当spri…

C 文件 fseek() 函数

C 文件 fseek() 函数 fseek()函数用于将文件指针设置为指定的偏移量。它用于将数据写入文件中所需的位置。 语法&#xff1a; int fseek(FILE *stream, long int offset, int whence)参数 第一个参数 stream 为文件指针 第二个参数 offset 为偏移量&#xff0c;整数表示正向…

activiti工作流 定义 TaskListener 无效

使用activiti 5.22 想全局定义任务监听器&#xff0c;结果试了多次发现没有效果。 最后看了看activiti的相关源码发现&#xff0c;流程定义里边没有处理 TaskListener 相关的操作&#xff0c;发现TaskListener 处理是在Task里边处理的&#xff0c;所以把TaskListener 定义在Ta…

【ISP】噪声--sensor(2)

1.热噪声 也叫KT/C噪声&#xff0c;或者叫暗电流噪声。电子的热运动的导致&#xff0c;温度上升&#xff0c;噪声增大。 2.FPN固定模式噪声 由于每个像素点的元器件制造的会有偏差&#xff0c;也就是这些器件的工作参数相对理论值的漂移就构成一种固定模式噪声。 3.光子散粒噪…

Springboot+vue的客户关系管理系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的客户关系管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的客户关系管理系统&#xff0c;采用M&#xff08…