React组件间通信

作者: 南风知我意ZD | 来源:发表于2019-06-08 14:18 被阅读11次

组件间不同的嵌套关系,会导致不同的通信方式。常见的有:父组件向子组件通信、子组件向父组件通信、没有嵌套关系的组件之间的通信,还有一种特殊形式:跨级组件通信。

1、父组件向子组件通信

这是React中最为常见的一种通信方式,父组件通过props向子组件传递需要的信息。示例如下:

class Child extends Component{
    render(){
        const { name } = this.props;
        return <p>hello, { name }</p>;
    }
}

class Parent extends Component{
    render(){
        return (
            <div>
                <Child name='Bob' />
            </div>
        );
    }
}

2、子组件向父组件通信

子组件向父组件通信有两种方式

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

相较而言回调函数更为简单,一般多用这种方式。其原理为:父组件将一个函数作为props传递给子组件,子组件调用这个回调函数,将想要传递的信息,作为参数,传递给父组件。示例如下:

class Parent extends Component{
    constructor(props){
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.state={
            visible: false。
        }
    }

    handleClick(){
        this.setState({
            visible: true,
        });
    }

    render(){
        return (
            <React.Fragment>
                <div style={{display: this.state.visible ? 'block' : 'none'}}>
                    我是被隐藏的文字
                </div>
                <Child name='Bob' handleClick={this.handleClick} />
            </React.Fragment>
        );
    }
}
class Child extends Component{
    render(){
        const { handleClick } = this.props;
        return (<button onClick={handleClick}>点击显示隐藏的文字</button>);
    }
}

3、跨级组件通信

跨级组件通信有两种方法:(1)向层层传递props。(2)利用context。

对于第一种方式,如果组件结构较深,那么中间每一层都需要传递props,增加了复杂度且造成了冗余。而context 相当于一个全局变量,是一个大容器,我们可以把要通信的内容放在这个容器中,这样一来,不管嵌套有多深,都可以随意取用。使用 context 也很简单,需要满足两个条件:

  • 上级组件要声明自己支持 context,并提供一个函数来返回相应的 context 对象
  • 子组件要声明自己需要使用 context

示例:

export default class GrandParent extends Component{
    // 父组件声明自己支持 context
    static childContextTypes = {
        color:PropTypes.string,
        callback:PropTypes.func,
    }

    // 父组件提供一个函数,用来返回相应的 context 对象
    getChildContext(){
        return{
            color:"red",
            callback:this.callback.bind(this)
        }
    }

    callback(msg){
        console.log(msg)
    }

    render(){
        return(
            <div>
                <Parent></Parent>
            </div>
        );
    }
}


const Parent = (props) =>{
    return(
        <div>
            <Child />
        </div>
    );
}


export default class Child extends Component{
    // 子组件声明自己需要使用 context
    static contextTypes = {
        color:PropTypes.string,
        callback:PropTypes.func,
    }

    render(){
        const style = { color:this.context.color }
        const handleConsoleLog = (msg) => {
            return () => {
                this.context.callback(msg);
            }
        }

        return(
            <div style = { style }>
                Child组件
                <button onClick = { handleConsoleLog("我胡汉三又回来了!") }>点击我</button>
            </div>
        );
    }
}

总结:如果是父组件向子组件单向通信,可以使用变量,如果子组件想向父组件通信,同样可以由父组件提供一个回调函数,供子组件调用,回传参数。

注意:如果组件中使用构造函数(constructor),还需要在构造函数中传入第二个参数 context,并在 super 调用父类构造函数是传入 context,否则会造成组件中无法使用 context。

constructor(props,context){
  super(props,context);
}

Context就像全局变量一样,而全局变量正是导致应用走向混乱的罪魁祸首之一,给组件带来了外部依赖的副作用,因此,不推荐使用context。其比较好的应用场景是:真正意义上的全局信息且不会更改,如界面主题,用户信息。总体原则是:如果真的需要使用,建议写成高阶组件来实现。

补充

1、context对象的更改。

我们不应该也不能直接改变context对象中的属性。要想改变 context 对象,只有让其和父组件的 state 或者 props 进行关联,在父组件的 state 或 props 变化时,会自动调用 getChildContext 方法,返回新的 context 对象,而后子组件进行相应的渲染。

    constructor(props) {
        super(props);
        this.state = {
            color:"red"
        };
    }
    // 父组件声明自己支持 context
    static childContextTypes = {
        color:PropTypes.string,
        callback:PropTypes.func,
    }

    // 父组件提供一个函数,用来返回相应的 context 对象
    getChildContext(){
        return{
            color:this.state.color,
            callback:this.callback.bind(this)
        }
    }

2、context同样可以引用在无状态组件上,只需将context作为第二个参数即可。

const Child = (props,context) => {
    const style = { color:context.color }
    const handleConsoleLog = (msg) => {
        return () => {
            context.callback(msg);
        }
    }

    return(
        <div style = { style }>
            Child组件
            <button onClick = { handleConsoleLog("我胡汉三又回来了!") }>点击我</button>
        </div>
    );
}

Child.contextTypes = {
    color:PropTypes.string,
    callback:PropTypes.func,
}

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

没有嵌套关系的组件通信包括兄弟组件通信和不在同一个父级中的非兄弟组件。同样有两种通信方式:

  • 利用二者共同父组件的context对象进行通信
  • 利用自定义事件

第一种方法利用父组件中转,会增加子组件和父组件之间的耦合度,如果组件层次较深,找到二者公共父组件不太容易。一般使用自定义事件实现。

自定义事件需要借用node.js的events模块:

安装:npm install events --save
引入:import { EventEmitter } from "events";
     export default new EventEmitter(); // 初始化实例并输出给其他组件使用
export default class App extends Component{
    render(){
        return(
            <div>
                <Foo />
                <Boo />
            </div>
        );
    }
}


export default class Foo extends Component{
    constructor(props) {
        super(props);
        this.state = {
            msg:null,
        };
    }
    componentDidMount(){
        // 声明一个自定义事件
        this.eventEmitter = emitter.on("callMe",(msg)=>{
            this.setState({
                msg,
            })
        });
    }
    // 组件销毁前移除事件监听
    componentWillUnmount(){
        emitter.removeListener(this.eventEmitter);
    }
    render(){
        return(
            <div>
                { this.state.msg }
                我是非嵌套 1 号
            </div>
        );
    }
}


export default class Boo extends Component{
    render(){
        const cb = (msg) => {
            return () => {
                // 触发自定义事件。参一为事件名,后面为传递给事件的参数,可多个。
                emitter.emit("callMe","Hello")
            }
        }
        return(
            <div>
                我是非嵌套 2 号
                <button onClick = { cb("blue") }>点击我</button>
            </div>
        );
    }
}

5、总结:

几种通信情况下,最适用的方式:

  • 父组件向子组件通信:使用 props
  • 子组件向父组件通信:使用 props 回调
  • 跨级组件间通信:使用 context 对象
  • 非嵌套组件间通信:使用事件订阅

相关文章

  • React组件间通信

    不借助redux等状态管理工具的React组件间的通信解决方法 组件通信分类 React组件间通信分为2大类,3种...

  • React学习拾遗2

    组件间通信: 龟兔赛跑-React组件间通信Demo:http://js.jirengu.com/yowec/ed...

  • React Native 架构之 Redux介绍

    React 在 React 中,UI 以组件的形式来搭建,组件之间可以嵌套组合。另,React 中组件间通信的数据...

  • React父子组件间通信的实现方式

    React学习笔记之父子组件间通信的实现:今天弄清楚了父子组件间通信是怎么实现的。父组件向子组件通信是通过向子组件...

  • (1)React的开发

    1、React项目架构搭建2、JSX语法3、React组件化开发4、React组件间通信5、React中的事件6、...

  • 「React Native」Event Bus,消息总线

    (一)父子间组件通信:   一般使用props,回调函数进行通信。(二)跨组件之间通信:  (1)React Na...

  • React组件间通信

    父组件向子组件 定义组件的方法就是通过React.createClass,当我们使用组件并且给其属性的时候,这个属...

  • react组件间通信

    React 开发模式是组件化开发, 所以组件间的信息传递就尤为重要,React传递数据的方式主要有3种。 prop...

  • react组件间通信

    react中的props和state props只读,用于组件之间传递信息,这个信息包括:数据和函数 state用...

  • react组件间通信

    处理 React 组件之间的交流方式,主要取决于组件之间的关系,然而这些关系的约定人就是你。 React 组件之间...

网友评论

    本文标题:React组件间通信

    本文链接:https://www.haomeiwen.com/subject/tdsixctx.html