React兄弟、父子元素之前的通信

本文介绍了React应用中不同组件间通信的方法,包括子组件向父组件传递数据的方式、父组件向子组件传递数据的过程以及如何利用这些机制实现兄弟组件间的间接通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

React元素之间的通信主要由下面几种方式
1、 Redux
2、 EventEmitter
3、 通过props进行通信(需要有嵌套关系)

这里面先记下来比较简单的第三种,因为最近刚刚用到。

子元素到父元素

父子元素之间的通信主要靠props,这个方法既简单,又好用,所以可以使用这种方法的时候就直接用好了。
首先有这样的一个React DOM结构:

<div className="passage">
     <NavBar   />
     <Passage />
</div>

渲染外层的div元素的时候,需要进行两个子组件的渲染,其中Passage组件的加载内容取决于NavBar当前的内容或者被点击后的内容,这里可以首先实现父元素和NavBar之间的通信过程,设置一个句柄,来帮助进行通信。

    constructor (props) {
        super(props);
        this.state = {
            currentPassage: ""
        }
        this.refreshCurrentPassage = this.refreshCurrentPassage.bind(this);
    }

    refreshCurrentPassage(cp) {
        this.setState({
            currentPassage: cp
        });
    }

上面的refreshCurrentPassage函数是这个通信过程的关键,我们将这个函数绑定当前父元素的this对象,并且将这个函数通过props传递给子元素:

    render() {
        return (
            <div className="passage">
                <NavBar  refreshCurrentPassage={this.refreshCurrentPassage} />
                <Passage currentPassage={this.state.currentPassage}/>
            </div>
        );
    }

子元素在其生命周期的componentDidMount阶段通过ajax获取当前页信息并且调用这个函数,将消息传递给父元素,这里需要注意React的生命周期,componentDidMount在官方给出的解释是:

Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.

注意是在初始化渲染之后执行一次的。如果你还有其他特殊需求的话可以在其他阶段来调用这个函数。

class NavUl extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            passage: []
        }
    }

    componentDidMount() {
    //在ajax请求成功之后调用一次更新父元素状态的函数,来完成一次父子元素之间的通信
        $.ajax({
            url: "../resources/data/passage.json",
            success: (data) => {
                this.setState({
                    passage: data.passages
                });
                this.props.refreshCurrentPassage(data.passages[0].passageName);
            }、
        });
    }

    render() {
        let liArray = [];
        this.state.passage.forEach((value,index) => {
            let liEle = <li key={value.passageName.toString()}>
                <a>
                    {value.passageName}({value.letterNum})&nbsp;author:{value.author}
                </a>
            </li>
            liArray.push(liEle);
        });
        return (
            <ul>
                {liArray}
            </ul>
        )
    }
}

class NavBar extends React.Component {
    constructor (props) {
        super(props);
    }

    render() {
        return (
            <nav>
                <NavUl refreshCurrentPassage={this.props.refreshCurrentPassage}/>
            </nav>
        );
    }
}

这样就完成了一次父子元素的通信过程。

父元素到子元素

父元素到子元素的状态通信更加简单了,可以直接使用props来进行传递。

//父元素的render函数
    render() {
        return (
            <div className="passage">
                <NavBar  refreshCurrentPassage={this.refreshCurrentPassage} />
                <Passage currentPassage={this.state.currentPassage}/>
            </div>
        );
    }

通过将自己的state的currentPassage属性传递给子元素的一个属性,也就是props对象,来告诉子元素加载某个模块。

class Passage extends React.Component {
    constructor (props) {
        super(props);

        this.state = {
            passage: ""
        }

    }
//子元素通过自己的this.props对象来进行访问,可以直接得到父元素传递的消息
    componentWillReceiveProps (nextProps) {
        let passageName = nextProps.currentPassage;
        passageName = passageName.toLowerCase().replace(" ", "");
        $.ajax({
            url: "../resources/data/" + passageName + ".json",
            success: (data) => {
                this.setState({
                    passage: data.passageContent
                });
            }
        });
    }

    render() {
        return (
            <article>
                <p>
                    {this.state.passage}
                </p>
            </article>
        );
    }
}

兄弟元素之间

上面的两个部分组合起来刚好就完成了兄弟元素之前的通信,其中一个子元素通过调用父元素传递过来的函数this.props.refreshCurrentPassage来修改父元素状态,然后在父元素状态修改之后,另外一个子元素的this.props会发生变化,从而触发重新渲染。这里需要注意的是React组件的声明周期,父元素到子元素通信由于可能需要多次渲染,所以使用了声明周期中的componentWillReceiveProps阶段来进行内容加载。在官方文档中是这么介绍这个阶段的:

Invoked when a component is receiving new props. This method is not called for the initial render.

也就是在一个组件接收了新的属性(props)触发的,这个方法不会在初始化渲染的时候触发。并且这个阶段还可以访问修改前的props对象。

### React组件通信方法 #### 父子组件通信React 中,父子组件间的通信是最基础也是最常用的一种形式。父组件可以通过 `props` 将数据传递给组件,在组件内部可以直接访问这些属性并用于渲染逻辑或执行特定的操作[^1]。 对于组件向父组件发送消息的情况,则通常采用回函数的形式来完成这一过程。具体来说就是在定义父级的时候预先设定好处理逻辑作为参数传入到孩那里去用[^3]。 ```jsx // 父组件 import React, { useState } from 'react'; import ChildComponent from './ChildComponent'; function ParentComponent() { const [messageFromChild, setMessageFromChild] = useState('No message yet'); const handleCallback = (childData) => { setMessageFromChild(childData); }; return ( <div> <h2>Parent Component</h2> <p>Message From Child: {messageFromChild}</p> <ChildComponent parentCallback={handleCallback} /> </div> ); } export default ParentComponent; // 组件 import React from 'react'; function ChildComponent({parentCallback}) { const sendDataToParent = () => { let dataForParent = "Hello Parent!"; parentCallback(dataForParent); //触发父组件中的回函数并将数据回传回去 } return( <button onClick={sendDataToParent}>Send Message to Parent</button> ) } ``` #### 兄弟组件通信 当涉及到同级别即兄弟关系的两个及以上控件相互交流时,除了借助共同祖先节点来进行间接性的联系外——比如让它们共享同一个状态管理工具像 Redux 或者 MobX 来同步彼此的状态变化;还可以利用上下文(Context API)[^5] 实现无须经过中间层就能直接交互的效果: - **使用 Context** 首先创建一个 context 对象,并通过 `<Provider>` 提供全局可获取的信息源,任何后代元素只要包裹了对应的 consumer 即能轻松读取所需资源而无需关心实际位置距离有多远。 ```javascript import React, { createContext, useContext, useState } from 'react'; const MyContext = createContext(); function SiblingOne(){ const value = useContext(MyContext); return (<div>Sibling One says: {value}</div>); } function SiblingTwo(){ const [, setGlobalValue] = useContext(MyContext); return(<button onClick={()=>{ setGlobalValue("New Value"); }}>Change Global State</button>) } function Container(){ const [globalState, setGlobalState] = useState("Initial Value"); return( <MyContext.Provider value={[globalState, setGlobalState]}> <SiblingOne/> <SiblingTwo/> </MyContext.Provider> ) } ``` #### 使用 Redux 进行复杂应用状态管理 针对大型项目里多个不相邻甚至跨越多层级结构的不同部分需要保持一致性和高效更新的需求,推荐引入专门设计用来解决这问题的状态管理模式—Redux。它允许开发者集中存储整个应用程序级别的变量及其变更历史记录,从而简化跨模块协作流程的同时也提高了代码维护性[^4]。 ```typescript // 定义action types enum ActionTypes { UPDATE_MESSAGE = 'UPDATE_MESSAGE', } interface IMessageAction { type: typeof ActionTypes.UPDATE_MESSAGE; payload: string; } // 创建reducer const commReducer = (state: string = "", action: IMessageAction): string => { switch(action.type){ case ActionTypes.UPDATE_MESSAGE: return action.payload; default: return state; } }; // 在store中注册此reducer... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值