React组件间通信

  • 1. 组件间通信
    • 1.1.父组件向子组件通信
    • 1.2.子组件向父组件通信
    • 1.3.跨级组件间通信
    • 1.4.无嵌套关系组件间通信

这周重点学习React的组件间通信。

1. 组件间通信

React的组件间通信可分为四种:

  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件间通信
  • 无嵌套关系组件间通信

1.1.父组件向子组件通信

因为React的数据流是单向流动的,所以父组件向子组件通信也是最常见的通信方式。父组件通过props向子组件传递数据。
举一个简单的例子:

子组件中:
import React from 'react';

export default function Child({ name }) {
    return 

Hello, {name}

; } 父组件中: import React, { Component } from 'react'; import Child from './Child'; class Parent extends Component { render() { return (
); } } export default Parent;

上述例子中父组件向子组件传递了name属性,在子组件中就可以用this.props.name的方式获取从父组件传来的name值。

1.2.子组件向父组件通信

子组件向父组件通信主要有两种方法:
1.利用回调函数:子组件更新组件状态,通过回调函数的方式传递给父组件。
2.利用自定义事件机制:这种方法更加通用广泛,加入事件机制可以简化组件API。
举个例子:

父组件中:定义回调函数
import React, { Component } from 'react';
import Child from './child.js'; 

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      msg: '父组件初始msg'
    }
  }

  //父组件回调函数,更新state,进而更新父组件。
  callback=(msg)=>{
    this.setState({msg});
  }

  render() {
    return (
      

子组件传值实验: {this.state.msg}

); } } export default App; 子组件中:调用父组件传来的回调函数,并把值通过回调函数传递给父组件。 import React from "react"; class Child extends React.Component{ constructor(props){ super(props); this.state={ msg: '子组件msg传值' } } //通过props调用回调函数传值 trans=()=>{ this.props.callback(this.state.msg); } render(){ return(
) } } export default Child;

上述例子中,在父组件中定义了一个回调函数,可以实时更新传入的参数为this.state中的值,然后在子组件中通过this.props.回调函数调用它,并把自己的this.state中的值传给这个回调函数,从而达到子组件向父组件传值的作用。

1.3.跨级组件间通信

在React中,可以使用context来实现跨级父子组件间的通信。context提供了一种组件之间共享数据的方式,可以避免数据在组件树上逐层传递,但大部分情况下,不推荐使用context,因为它属于全局变量,容易引起结构混乱。如果真的需要使用,建议写成高阶组件来实现。
注:


Context API的使用基于生产者消费者模式。
生产者一方,通过组件静态属性childContextTypes声明,然后通过实例方法getChildContext()创建Context对象。
消费者一方,通过组件静态属性contextTypes申请要用到的Context属性,然后通过实例的context访问Context的属性。


举个例子:

生产者:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import CppComponent from './Cpp.js';

class App extends Component {

  constructor(props){
    super(props);
  }

  //Context生产者,通过静态属性childContextTypes声明提供给子组件的Context对象的属性,
  static childContextTypes = {
    propA: PropTypes.string
  }
  
  //实例getChildContext方法,返回Context对象
  getChildContext () {
    return {
      propA: 'propA'
    }
  }

  render() {
    return 
  }
}

class BppComponent extends React.Component {
  render () {
    return 
  }
}

export default App;

消费者:
import React, { Component } from 'react';
import PropTypes from 'prop-types'

/**
 * 第三层有A(生产者)层直接传递数据到此层C(消费者)
 */
class CppComponent extends React.Component {
   //子组件需要通过一个静态属性contextTypes声明后,才可以访问父组件Context对象的属性
  static contextTypes = {
    propA: PropTypes.string
  }

  render () {
    return(
      

从生产者传递过来的属性A:{this.context.propA}

) } } export default CppComponent;

上面的例子其实就运用了高阶组件,高阶组件说通俗点就是一个函数,它接受一个React组件作为参数输入,然后输出一个新的React组件。

1.4.无嵌套关系组件间通信

非嵌套组件: 就是没有任何包含关系的组件,包括兄弟组件以及不再同一个父级的非兄弟组件。
使用事件订阅,即一个发布者,一个或多个订阅者。
这里我们借用Node.js Events 模块的浏览器版实现。

  1. 安装event
   npm install event -save
  1. 新建Evt.js, 创建EventEmitter 实例
   import { EventEmitter } from 'events'; 
   export default new EventEmitter();
  1. 发布者通过emit事件触发方法,发布订阅消息给订阅者,把 EventEmitter 实例输出到各组件中使用;
    订阅者通过emitter.addListener(事件名称,函数名)方法,进行事件监听(订阅);通过emitter.removeListener(事件名称,函数名)方法 ,进行事件销毁(取消订阅)
    举例:
  发布者:
  import React, { Component } from 'react';
  import PropTypes from 'prop-types';
  import Custom1 from './Custom1.js';
  import Custom2 from './Custom2.js';
  import emitter from './Evt.js';

  class App extends Component {

    constructor(){
      super();
      this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
      //emit事件触发方法,通过事件名称找对应的事件处理函callCustom,将事件处理函数作为参数传入
      emitter.emit('callCustom', 'Hello 我来发消息了');
    }

    render() {    
      return(
        

) } } export default App; 订阅者1 Custom1: import React from 'react'; import ReactDOM from 'react-dom'; import emitter from './Evt.js'; class Custom1 extends React.Component { constructor(){ super(); this.state= { msg:'' } } componentDidMount () { //在组件挂载完成后声明一个自定义事件 emitter.addListener('callCustom', (msg) => { this.setState({ msg: 'Custom1收到消息--'+msg }); }) } componentWillUnmount () { //组件销毁前移除事件监听 emitter.removeListener('callCustom', (msg) => { this.setState({ msg: 'Custom1即将销毁此消息--'+ msg }); }) } //订阅者1消息显示 render () { return(

{this.state.msg}

) } } export default Custom1; 订阅者2 Custom2: import React from 'react'; import ReactDOM from 'react-dom'; import emitter from './Evt.js'; class Custom2 extends React.Component { constructor(){ super(); this.state= { msg:'' } } componentDidMount () { //在组件挂载完成后声明一个自定义事件 emitter.addListener('callCustom', (msg) => { this.setState({ msg: 'Custom2收到消息--'+msg }) }) } componentWillUnmount () { //组件销毁前移除事件监听 emitter.removeListener('callCustom', (msg) => { this.setState({ msg: 'Custom2即将销毁此消息--'+ msg }) }) } //订阅者2消息显示 render () { return(

{this.state.msg}

) } } export default Custom2;

最终预览效果如下图:


你可能感兴趣的:(React组件间通信)