React 组件间通信方式详解

487 阅读3分钟

如果文中有出现纰漏、错误之处,还请大神您多指教。 本文将通过实例的方式记录一下 React 中组件之间的通信方式。

在 React中,需要组件通信的情况一般有以下几种:

父组件向子组件通信 子组件向父组件通信 跨级组件通信 没有嵌套关系组件之间的通信

React数据流动是单向的,父组件向子组件通信也是最常见的。父组件通过 props 向子组件传递需要的信息。 1. 父组件向子组件通信

父组件

import React from 'react'
import TextItem from "../components/TextItem/TextItem"

class Page extends React.Component {
    render() {
        return (
            <div>Hello , <TextItem text='小忆技术体验设计团队'/></div>
        );
    }
}

export default Page

子组件

import React from 'react'

class TextItem extends React.Component {
    render() {
        const {text} = this.props
        return (
            <p>{text}</p>
        );
    }
}

export default TextItem

2. 子组件向父组件通信

利用回调函数、自定义事件机制

父组件

import React from 'react'
import TextItem from "../components/TextItem/TextItem";

class Page extends React.Component {
    handleClick() {
        console.log('小忆技术体验设计团队')
    }

    render() {
        return (
            <div>Hello , <TextItem text='小忆技术体验设计团队' onClick={() => this.handleClick()}/></div>
        );
    }
}

export default Page

子组件

import React from 'react'

class TextItem extends React.Component {
    render() {
        const {text, onClick} = this.props
        return (
            <p onClick={onClick ? onClick : null}>{text}</p>
        );
    }
}

export default TextItem

3. 跨级组件通信

层层组件传递 props 例如A组件和B组件之间要进行通信,先找到A和B公共的父组件,A先向C组件通信,C组件通过 props 和B组件通信,此时C组件起的就是中间件的作用。 举个栗子,上代码。

A 组件

import React from 'react'

class A extends React.PureComponent {
    state = {
        a:'我是 A 里传过来的内容'
    }

    handleClick() {
        const {a} = this.state
        const {onClick} = this.props
        onClick ? onClick(a) : null
    }
    render() {
        return (
            <div onClick={()=>this.handleClick()}>我是A:点我把内容传给B</div>
        );
    }
}

export default A

B 组件

import React from 'react'

class B extends React.PureComponent {

    render() {
        const {txt} = this.props

        return (
            <div>我是B:{txt}</div>
        );
    }
}

export default B

C 组件

import React from 'react'
import A from "./A";
import B from "./B";

class C extends React.PureComponent {

    state = {
        str: ''
    }

    handleClick(txt) {
        this.setState({
            str: txt
        })
    }

    render() {
        return (
            <div>
                <A onClick={t => this.handleClick(t)}/>
                <B txt={this.state.str}/>
            </div>
        );
    }
}

export default C

使用context

在React中子组件跨级访问时,我们可以通过层层传递的方法,但是这样代码不优雅而且当代码多的情况下有些冗余。这时我们可以通过context实现跨级父子组件间的通信。

import React from 'react'

const TextContext = React.createContext('text')

class C extends React.PureComponent {

    render() {
        return (
            <TextContext.Provider value="小忆技术体验设计团队">
                <D/>
            </TextContext.Provider>
        )
    }
}

class D extends React.PureComponent {

    render() {
        return (
            <div><E/></div>
        )
    }
}
class E extends React.PureComponent {
    static contextType = TextContext;

    render() {
        return (
            <div>{this.context}</div>
        )
    }
}

export default C

4. 没有嵌套关系的组件通信

使用自定义事件机制 举个栗子,page2 要去改 page1 的文字,上代码。 先在项目中安装 events

npm i -D events

在 src 下新建一个 utils 目录,里面建一个 events.js

import { EventEmitter } from 'events';

export default new EventEmitter();

Page1

import React, { Component } from 'react';
import emitter from '../utils/events';

class Page1 extends Component {
    constructor(props) {
        super(props);
        this.state = {
            message: 'Page1',
        };
    }
    componentDidMount() {
        // 组件装载完成以后声明一个自定义事件
        this.eventEmitter = emitter.addListener('changeMessage', (message) => {
            this.setState({
                message,
            });
        });
    }
    componentWillUnmount() {
        emitter.removeListener(this.eventEmitter);
    }
    render() {
        return (
            <div>
                {this.state.message}
            </div>
        );
    }
}

export default Page1;

Page2

import React, {Component} from 'react';
import emitter from '../utils/events';

class Page2 extends Component {
    handleClick = (message) => {
        emitter.emit('changeMessage', message);
    };

    render() {
        return (
            <div>
                <button onClick={() => this.handleClick('Page2')}>点击我改变Page1组件中显示信息</button>
            </div>
        );
    }
}

export default Page2