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

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>
    );
}


http://www.kler.cn/a/457795.html

相关文章:

  • 组会 | DenseNet
  • ​​​​​​​CDP集群安全指南系列文章导读
  • 自学记录鸿蒙API 13:实现多目标识别Object Detection
  • Qemu配置QXL显卡支持分辨率
  • 安卓11 SysteUI添加按钮以及下拉状态栏的色温调节按钮
  • Spring源码分析之事件机制——观察者模式(二)
  • RAG挑战及其解决方案:实践中的应对策略
  • 嵌入式单片机窗口看门狗控制与实现
  • 【AIGC-ChatGPT副业提示词指令 - 动图】命运织图:一个创新的个人发展分析工具
  • Ajax笔记
  • SCAU高程期末课后习题复习(只放了易错自用)
  • 探索城市空中交通的未来:基于Python的仿真与优化
  • Zookeeper JavaAPI操作(Curator API常用操作)
  • 探索 JavaBean(实体类)的奇妙世界
  • VSCode outline显示异常的解决方法——清除VSCode的配置和用户文件
  • AI生成PPT,效率革命的新时代
  • 数据的简单处理——pandas模块——查看数据
  • RedisDesktopManager新版本不再支持SSH连接远程redis后
  • PCIe和DMA:数据传输的“双子星“
  • 集成学习(模型融合)
  • 解锁仓颉编程语言的奥秘:枚举类型、模式匹配与类接口全解析
  • xss csrf怎么预防?
  • 大厂开发规范-如何规范的提交Git
  • winserver搭建域环境
  • 前端实现图片压缩插件(image-compressorionjs)
  • mybatis-plus 用法总结