React 组件间的通信示例


Posted in Javascript onJune 14, 2018

前言

从官网上也有介绍组件间如何通信,但不够详细,这里做个小结,方便对比和回顾

本文内容

处理组件之间的通信, 主要取决于组件之间的关系,因此我们划分为以下三种:

  1. 【父组件】向【子组件】传值;
  2. 【子组件】向【父组件】传值;
  3. 【组件A】向无关系【组件B】传值,一般为兄弟组件;

一、「父组件」向「子组件」传值

这是最普遍的用法,实现上也非常简单,主要是利用props来实现

// 父组件
import React from 'react';
import Son from './components/son';
class Father extends React.Component {
  constructor(props) {
    // 这里要加super,否则会报错
    super(props);
    this.state = {
      checked: true
    }
  }

  render() {
    return (
      <Son text="Toggle me" checked={this.state.checked} />
    )
  }
}
// 子组件
class Son extends React.Component {
  render() {
    // 接收来自父组件的参数
    let checked = this.props.checked,
      text = this.props.text;
    return (
      <label>{text}: <input type="checkbox" checked={checked} /></label>
    )
  }
}

多想一点:

如果组件的嵌套层次太多,那么从外到内的交流成本就会加深,通过 props 传值的优势就不明显,因此,我们还是要尽可能的编写结构清晰简单的组件关系, 既也要遵循组件独立原则,又要适当控制页面,不可能或极少可能会被单用的代码片,可不编写成一个子组件

二、「子组件」向「父组件」传值

我们知道,react的数据控制分为两种,为 props 和 state;其中,props 如上刚介绍过,它是父组件向子组件传值时作为保存参数的数据对象;而 state 是组件存放自身数据的数据对象。这两者最主要的区别就是,props属于父组件传给子组件的只读数据,在子组件中不能被修改,而state在自身组件中使用时,可以通过setState来修改更新。

子组件向父组件传值,需要控制自己的state,并发起父组件的事件回调来通知父组件

// 父组件
import Son from './components/son';
class Father extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      checked: false
    }
  }
  onChildChanged() {
    this.setState({
      checked: newState
    })
  }

  render() {
    let isChecked = this.state.checked ? 'yes' : 'no';
    return (
      <div>
        <span>Are you checked: {isChecked }</span>
        <Son text="Toggle me" 
           initialChecked={this.state.checked}
           callbackParent={this.onChildChanged.bind(this)}
         ></Son>
      </div>
    )
  }
}
// 子组件
class Son extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: this.props.initialChecked
    }
  }
  onTextChange() {
    let newState = !this.state.check.checked;
    this.setState({
      checked: newState
    });
    // 注意,setState 是一个异步方法,state值不会立即改变,回调时要传缓存的当前值,   
    // 也可以利用传递一个函数(以上传的是对象),并传递prevState参数来实现数据的同步更新
    this.props.callbackParent(newState);
  }
  render() {
    let text= this.props.text;
    let checked = this.state.checked;
    return (
      <label>{text}: <input type="checkbox" checked={checked} onChange={this.onTextChange.bind(this)}></label>
    )
  }
}

多想一点:

  1. 同样应当避免深层次的组件嵌套
  2. 这里其实是依赖了props来传递事件的引用,并通过回调的方式来实现,在没有使用工具情况下,可以使用该办法

拓展一点:

在onChange 事件或者其他React事件中,你能获取以下信息:

  1. 「this」 指向你的组件
  2. 「一个参数」 一个react合成事件, SyntheticEvent

我们知道,React对所有事件的管理都是自己封装实现的,html中的 onclick 被封装成了 onClick, onchange 被封装成了 onChange。从根本上来说,他们都是被绑定在body上的。

多个子组件回调同一个回调函数情况

父组件中大概率包含多个子组件,为节省和简洁代码,遵循 don't repeat yourself 原则,我们会让一个回调函数实现多个子组件的功能,或多个组件协作完成指定功能

import React from 'react';
import Son from './components/son';
class Father extends React.Componnet {
  constructor(props) {
    super(props);
    this.state = {
      totalChecked: 0
    }
  }
  onChildChangeed() {
    let newTotal = this.state.totalChecked + (new State ? 1 : -1 );
    this.setState({
       totalChecked = this.state.totalChecked;
    });
  }
  render() {
    return (
      <div>
        <div>Checked numbers: {this.state.totalChecked}</div>
        <Son text="Toggle me" initialChecked={this.state.checked} callbackParent={this.onChildChanged} />
        <Son text="Toggle me too" initialChecked={this.state.checked} callbackParent={this.onChildChanged} />
         <Son text="Add me" initialChecked={this.state.checked} callbackParent={this.onChildChanged} />
      </div>
    )
  }
}
// 子组件
class Son extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: this.props.initialChecked
    }
  } 

  onTextChange() {
    let newState = !this.state.checked;
    this.setState({
      checked: newState
    })
    // setState异步方法问题,注意传值
    this.props.callbackParent(newState);
  }

  render() {
    let text = this.props.checked;
    let checked = this.state.checked;
    return {
      <label>{text}: <input type="checkbox" checked={checked} onChange={this.onTextChange.bind(this)} /></label>
    }
  }
}

多想一点:

在本案例中,我们引用了三个 Son 子组件, 每个 Son 组件都独立工作互不干扰,该例中,增加了一个 totalChecked 来替代之前的 checked, 当组件触发onTextChange 后,触发父组件的回调函数使得父组件的值得以改变。

三、组件A和无关系组件B之间的通信

如果组件之间没有任何关系,或者组件嵌套的层次比较深,或者,你为了一些组件能够订阅,写入一些信号,不想让两个组件之间插入一个组件,而是让两个组件出于独立的关系。对于时间系统,有两个基本操作:

  1. 订阅: subscribe
  2. 监听: listen

并发送 send / 触发 trigger / 发布 publish / 发送 dispatch 通知那些想要的组件

1. Event Emitter/Target/Dispatcher

特点: 需要一个指定的订阅源

// to subscribe
otherObiect.addEventListener('clickEvent', function() {
  alert('click!');
})
// to dispatch
this.dispatchEvent('clickEvent');

2. Publish / Subscribe

特点: 触发的时候,不需要指定一个特定的源,使用全局对象广播的方式来处理事件

// to subscribe
globalBroadcaster.subcribe('clickEvent', function() {
  alert('cilck!');  
})
// to publish
globalBroadcaster.publish('clickEvent');

这种方案还有一个插件可用, 即 PubSubJs;用法如下:

import Pubsub from 'pubsub-js';
...
// to subscribe
Pubsub.subscribe('EVENT', (msg, param) => {
  console.log(msg, param);
});
// to publish
Pubsub.publish('EVENT', param);

3. Single

特点: 与 Event Emitter/Target/Dispatcher 类似,但是不要使用随机字符串作为事件触发的引用。触发事件的每一个对象都需要一个确切的名字,并且在触发的时候,也必须要指定确切的事件

// to subscribe
otherObject.clicked.add(function() {
  alert('click');
})
// to dispatch
this.clicked.dispatch();

React 团队使用的是:js-signals 它基于 Signals 模式,用起来相当不错。

事件订阅与取消

使用React事件的时候,必须关注以下两个方法:

  1. componentDidMount
  2. componentWillUnmount

在 componentDidMount 事件中,等待组件挂载 mounted 完成,再订阅事件;订阅的事件需要在组件卸载 componentWillUnmount 的时候取消事件的订阅。

因为组件的渲染和销毁是有 React 来控制的,我们不知道怎么引用他们,所以EventEmitter 模式在处理事件的时候用处不大,Pub/Sub 模式就好用些,因为我们不需要知道引用在哪。

ES6策略: yield and js-csp

ES6中有一种传递信息的方式,使用生成函数 generators 和 yield 关键字,用法参考以下例子

import csp from 'js-csp';

function* list() {
  for(var i = 0; i< arguments.length; i++) {
    yield arguments[i];
  }
  return "done";
}
var o = list(1, 2, 3);
var cur = o.next;
while (!cur.done) {
  cur = o.next();
  console.log(cur);
}

结束语

数据在组件中应该以什么样的方式进行传递取决于组件之间存在什么样的关系和当时的业务场景需求,大家应该根据项目合理选择数据处理的方案,这很可能减少你大量的代码量和代码逻辑。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的二级联动菜单实现代码
Apr 25 Javascript
Android中资源文件(非代码部分)的使用概览
Dec 18 Javascript
jquery实现metro效果示例代码
Sep 06 Javascript
容易造成JavaScript内存泄露几个方面
Sep 04 Javascript
JS脚本根据手机浏览器类型跳转WAP手机网站(两种方式)
Aug 04 Javascript
angularjs表格ng-table使用备忘录
Mar 09 Javascript
javascript实现列表切换效果
May 02 Javascript
原生js实现轮播图的示例代码
Feb 20 Javascript
vue使用watch 观察路由变化,重新获取内容
Mar 08 Javascript
vue-resource请求实现http登录拦截或者路由拦截的方法
Jul 11 Javascript
ES6函数实现排它两种写法解析
May 13 Javascript
Jquery ajax书写方法代码实例解析
Jun 12 jQuery
三分钟学会用ES7中的Async/Await进行异步编程
Jun 14 #Javascript
详解React中setState回调函数
Jun 14 #Javascript
JavaScript 判断对象中是否有某属性的常用方法
Jun 14 #Javascript
Vue.js添加组件操作示例
Jun 13 #Javascript
vue 项目打包通过命令修改 vue-router 模式 修改 API 接口前缀
Jun 13 #Javascript
clipboard.js在移动端复制失败的解决方法
Jun 13 #Javascript
ES6与CommonJS中的模块处理的区别
Jun 13 #Javascript
You might like
PHP 命令行工具 shell_exec, exec, passthru, system详细使用介绍
2011/09/11 PHP
php解析html类库simple_html_dom(详细介绍)
2013/07/05 PHP
thinkphp框架使用JWTtoken的方法详解
2019/10/10 PHP
JavaScript 实现??打印?理
2007/04/28 Javascript
window.location.hash 使用说明
2010/11/08 Javascript
javascript实现分栏显示小技巧附图
2014/10/13 Javascript
DOM基础教程之使用DOM + Css
2015/01/20 Javascript
Javascript中With语句用法实例
2015/05/14 Javascript
JavaScript实现函数返回多个值的方法
2015/06/09 Javascript
jQuery链式操作实例分析
2015/11/16 Javascript
详细讲解vue2+vuex+axios
2017/05/27 Javascript
Node实战之不同环境下配置文件使用教程
2018/01/02 Javascript
vue路由组件按需加载的几种方法小结
2018/07/12 Javascript
JS实现选项卡效果的代码实例
2019/05/20 Javascript
vue项目出现页面空白的解决方案
2019/10/31 Javascript
[05:10]2014DOTA2国际邀请赛 通往胜利之匙赛场探秘之旅
2014/07/18 DOTA
[01:14]DOTA2亚洲邀请赛 ShowOpen
2015/02/07 DOTA
[01:54]TI珍贵瞬间系列(五):压力
2020/08/29 DOTA
python3如何将docx转换成pdf文件
2018/03/23 Python
pytorch cnn 识别手写的字实现自建图片数据
2018/05/20 Python
利用Python如何生成便签图片详解
2018/07/09 Python
python打开windows应用程序的实例
2019/06/28 Python
对Django外键关系的描述
2019/07/26 Python
浅谈ROC曲线的最佳阈值如何选取
2020/02/28 Python
Python requests模块session代码实例
2020/04/14 Python
Python实现图片指定位置加图片水印(附Pyinstaller打包exe)
2021/03/04 Python
雪花秀美国官方网站:韩国著名草本护肤化妆品品牌
2016/10/19 全球购物
加拿大服装和鞋类零售商:Mark’s
2021/01/04 全球购物
详解如何解决使用JSON.stringify时遇到的循环引用问题
2021/03/23 Javascript
人力资源部副职的竞聘演讲稿
2014/01/07 职场文书
财务内勤岗位职责
2014/04/17 职场文书
银行爱岗敬业演讲稿
2014/05/05 职场文书
大型主题婚礼活动策划方案
2014/09/15 职场文书
2015年办公室工作总结范文
2015/03/31 职场文书
Python游戏开发实例之graphics实现AI五子棋
2021/11/01 Python
MongoDB使用场景总结
2022/02/24 MongoDB