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获取被勾选的checked(选中)的那一行的3列和4列的值
Jul 04 Javascript
Jquery 的outerHeight方法使用介绍
Sep 11 Javascript
鼠标滚轮改变图片大小的示例代码
Nov 20 Javascript
js实现有时间限制消失的图片方法
Feb 27 Javascript
asp.net+jquery.form实现图片异步上传的方法(附jquery.form.js下载)
May 05 Javascript
详细总结Javascript中的焦点管理
Sep 17 Javascript
Angularjs 双向绑定时字符串的转换成数字类型的问题
Jun 12 Javascript
JS实现自定义弹窗功能
Aug 08 Javascript
详解vue 项目白屏解决方案
Oct 31 Javascript
js中复选框的取值及赋值示例详解
Oct 18 Javascript
antd 表格列宽自适应方法以及错误处理操作
Oct 27 Javascript
react如何快速设置文件路径别名
Apr 28 Javascript
三分钟学会用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
mysql_fetch_assoc和mysql_fetch_row的功能加起来就是mysql_fetch_array
2007/01/15 PHP
str_replace只替换一次字符串的方法
2013/04/09 PHP
ThinkPHP框架实现FTP图片上传功能示例
2019/04/08 PHP
JavaScript 获取用户客户端操作系统版本
2009/08/25 Javascript
Jquery实现仿新浪微博获取文本框能输入的字数代码
2013/02/22 Javascript
DWZ刷新dialog解决方法
2013/03/03 Javascript
JavaScript 里的类数组对象
2015/04/08 Javascript
纯javaScript、jQuery实现个性化图片轮播【推荐】
2017/01/08 Javascript
详解Vue方法与事件
2017/03/09 Javascript
JS实现的模仿QQ头像资料卡显示与隐藏效果
2017/04/07 Javascript
JavaScript订单操作小程序完整版
2017/06/23 Javascript
JS使用Prim算法和Kruskal算法实现最小生成树
2019/01/17 Javascript
解决echarts中横坐标值显示不全(自动隐藏)问题
2020/07/20 Javascript
Python中使用ConfigParser解析ini配置文件实例
2014/08/30 Python
Python两个内置函数 locals 和globals(学习笔记)
2016/08/28 Python
python解决字符串倒序输出的问题
2018/06/25 Python
python 同时运行多个程序的实例
2019/01/07 Python
python计算阶乘和的方法(1!+2!+3!+...+n!)
2019/02/01 Python
numpy ndarray 取出满足特定条件的某些行实例
2019/12/05 Python
python 实现将list转成字符串,中间用空格隔开
2019/12/25 Python
NumPy统计函数的实现方法
2020/01/21 Python
使用 Python 在京东上抢口罩的思路详解
2020/02/27 Python
找Python安装目录,设置环境路径以及在命令行运行python脚本实例
2020/03/09 Python
5 分钟读懂Python 中的 Hook 钩子函数
2020/12/09 Python
python 基于opencv实现图像增强
2020/12/23 Python
使用CSS3制作饼状旋转载入效果的实例
2015/06/23 HTML / CSS
HTML5中Localstorage的使用教程
2015/07/09 HTML / CSS
探索HTML5本地存储功能运用技巧
2016/03/02 HTML / CSS
TripAdvisor土耳其网站:全球知名旅行社区,真实旅客评论
2017/04/17 全球购物
英国领先的在线高尔夫商店:Scottsdale Golf
2019/08/26 全球购物
计算机应用与科学个人的自我评价
2013/11/15 职场文书
倡导文明标语
2014/06/16 职场文书
2015年学校少先队工作总结
2015/07/20 职场文书
2016年庆祝六一儿童节活动总结
2016/04/06 职场文书
Java SSH 秘钥连接mysql数据库的方法
2021/06/28 Java/Android
海贼王十大逆天果实 魂魂果实上榜,岩浆果实攻击力最强
2022/03/18 日漫