React 组件间通信

React作为前端的新一代主流框架,因其组件化的思想,彻底革新了前端停留在DOM操作的古老开发方式。使用React的组件,不再需要模板,也不用再过分担心渲染和更新带来的性能问题。开发一个个组件,就像一个个模块一般,在需要的地方放在那里就好。但是这么多的组件之间,如何进行信息交流和信息传递,就引发了一个新的问题——组件通信。

我是目录

  1. 事件通信
  2. 观察者模式
  3. 关于Redux与Flux

首先,我们先假设我们的组件结构如下:

      Parent
     ____|____
     |       |
  ChildA  ChildB

1. 事件通信

1.1 父传子

React 中,父组件可以向子组件通过传 props 的方式,向子组件进行通讯。

class Parent extends Component {
  state = { msg: 'start' };

  componentDidMount() {
    setTimeout(() => { this.setState({ msg: 'end' }); }, 1000);
  }

  render() {
    // 将传递值当做组件的props属性传递给子组件
    // return ;
    // 使用...运算符将父组件信息以更简洁的方式传递给子组件
    return ;
  }
}

class ChildA extends Component {
  render() {
    // 获取父组件传递过来的数据中的msg
    return 

{this.props.msg}

; } } export default Parent;

1.2 子传父

子组件向父组件通讯,同样也需要父组件向子组件传递 props 进行通讯,只是父组件传递的,是作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到父组件的作用域中。

class Parent extends Component {
  state = { msg: 'start' };

  transferMsg(childMsg) {
    this.setState({ msg: childMsg });
  }

  render() {
    return (
      

{this.state.msg}

// 将事件传递给子组件,子组件通过事件传递参数与父组件通信 this.transferMsg(childMsg)} />
); } }; class ChildA extends Component { componentDidMount() { setTimeout(() => { this.props.transferMsg('end'); }, 1000); } render() { return
; } }

1.3 兄弟组件通信

对于没有直接关联关系的两个节点,就如 ChildAChildB 之间的关系,他们唯一的关联点,就是拥有相同的父组件。参考之前介绍的两种关系的通讯方式,如果我们向由 ChildAChildB 进行通讯,我们可以先通过 ChildAParent 组件进行通讯,再由 ParentChildB 组件进行通讯。

class Parent extends Component {
  state = { msg: 'parent' };

  transferMsg(childAMsg) {
    this.setState({ msg: childAMsg });
  }

  componentDidUpdate() {
    console.log('Parent is update'); // 测试更新State后哪些组件也被更新了生命周期
  }

  render() {
    return (
      
this.transferMsg(childAMsg)} />
); } } class ChildA extends Component { componentDidMount() { setTimeout(() => { this.props.transferMsg('ChildA'); }, 1000); } componentDidUpdate() { console.log('ChildA is update'); // 测试更新State后哪些组件也被更新了生命周期 } render() { return
; } } class ChildB extends Component { componentDidUpdate() { console.log('ChildB update'); // 测试更新State后哪些组件也被更新了生命周期 } render() { return (

I am ChildB, this is ChildA to parent and then to ChildB: {this.props.msg}

); } } class ChildBchild extends Component { componentDidUpdate() { console.log('ChildBchild is update'); // 测试更新State后哪些组件也被更新了生命周期 } render() { return
; } }

当我们在浏览器运行时,可以从控制台发现,各个组件的 componentDidUpdate 方法均被触发。所以,有没有更好的解决方式呢?

2. 观察者模式

观察者模式也叫发布-订阅者模式,发布者发布事件,订阅者监听事件并做出反应。我们通过这种模式,在全局定义一个事件代理管理器,每一个组件只需要引入这个事件代理者即可。

事件代理文件,eventBus.js

const eventBus = {
  onObj: {},
  // 事件监听
  on(key, fn) {
    this.onObj[key] === undefined && (this.onObj[key] = []);
    this.onObj[key].push(fn);
  },
  // 事件关闭
  off(key) {
    this.onObj[key] = [];
    this.oneObj[key] = [];
  },
  // 事件触发
  trigger() {
    /*
      备注:
      除了事件参数,其他参数允许传入数组,但对于传入的map结构、函数、以及多个其他参数都没有做处理,
      这点可以根据个人需要进行拓展
    */
    // 无参返回false
    if (arguments.length === 0) {
      return false;
    }
    // key是事件,args是参数 - 通信信息
    const argumentsArr = [...arguments];
    let key = argumentsArr[0];
    let args = argumentsArr.slice(1);

    if (this.onObj[key] !== undefined && this.onObj[key].length > 0) {
      for (let i in this.onObj[key]) {
        this.onObj[key][i].apply(null, args);
      }
    }
  }
};

export default eventBus;

事件代理文件,eventBus.js

class Parent extends Component {
  render() {
    return (
      
); } } class ChildA extends Component { componentDidMount() { let hello = 'ChildA - 结束'; setTimeout(() => { eventBus.trigger('change', hello); }, 1000); } render() { return
; } } class ChildB extends Component { state = { msg: 'ChildB - 开始' }; componentDidMount() { eventBus.on('change', msg => { this.setState({ msg }); }); } render() { return (

ChildA to ChildB component: {this.state.msg}

); } }

3. 关于Redux与Flux

关于 ReduxFlux 就是用来管理状态和解决组件通信问题的。但虽然 Redux 对于组件间的解耦提供了很大的便利,如果你在考虑该不该使用 Redux 的时候,社区里有一句话说,“当你不知道该不该使用 Redux 的时候,那就是不需要的”。Redux 用起来一时爽,重构或者将项目留给后人的时候,就是个大坑,Redux 中的 dispatchsubscribe 方法遍布代码的每一个角落。虽然 Flux 设计中的 Controller-Views 概念就是为了解决这个问题出发的,将所有的 subscribe 都置于 Parent 组件(Controller-Views),由最上层组件控制下层组件的表现,然而,这不就是我们所说的子组件向父组件通讯这种方式了。

参考来源:淘宝-React组件通信原理

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