关于react中组件通信的几种方式详解


Posted in Javascript onDecember 10, 2017

前言

刚入门React可能会因为React的单向数据流的特性而遇到组件间沟通的麻烦,下面这篇文章就来给大家详细介绍下,在开始之前先来看一张图:

关于react中组件通信的几种方式详解

react组件通信

  • 需要组件之进行通信的几种情况
  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件通信
  • 没有嵌套关系组件之间的通信

1. 父组件向子组件通信

React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过props向子组件传递需要的信息
Child.jsx

import React from 'react';
import PropTypes from 'prop-types';
export default function Child({ name }) {
 return <h1>Hello, {name}</h1>;
}
Child.propTypes = {
 name: PropTypes.string.isRequired,
};

Parent.jsx

import React, { Component } from 'react';
import Child from './Child';
class Parent extends Component {
 render() {
  return (
   <div>
    <Child name="Sara" />
   </div>
  );
 }
}
export default Parent;

2. 子组件向父组件通信

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

回调函数

实现在子组件中点击隐藏组件按钮可以将自身隐藏的功能

List3.jsx

import React, { Component } from 'react';
import PropTypes from 'prop-types';
class List3 extends Component {
 static propTypes = {
  hideConponent: PropTypes.func.isRequired,
 }
 render() {
  return (
   <div>
    哈哈,我是List3
    <button onClick={this.props.hideConponent}>隐藏List3组件</button>
   </div>
  );
 }
}
export default List3;

App,jsx

import React, { Component } from 'react';
import List3 from './components/List3';
export default class App extends Component {
 constructor(...args) {
  super(...args);
  this.state = {
   isShowList3: false,
  };
 }
 showConponent = () => {
  this.setState({
   isShowList3: true,
  });
 }
 hideConponent = () => {
  this.setState({
   isShowList3: false,
  });
 }
 render() {
  return (
   <div>
    <button onClick={this.showConponent}>显示Lists组件</button>
    {
     this.state.isShowList3 ?
      <List3 hideConponent={this.hideConponent} />
     :
     null
    }
   </div>
  );
 }
}

观察一下实现方法,可以发现它与传统回调函数的实现方法一样.而且setState一般与回调函数均会成对出现,因为回调函数即是转换内部状态是的函数传统;

3. 跨级组件通信

层层组件传递props

例如A组件和B组件之间要进行通信,先找到A和B公共的父组件,A先向C组件通信,C组件通过props和B组件通信,此时C组件起的就是中间件的作用

使用context

context是一个全局变量,像是一个大容器,在任何地方都可以访问到,我们可以把要通信的信息放在context上,然后在其他组件中可以随意取到;

但是React官方不建议使用大量context,尽管他可以减少逐层传递,但是当组件结构复杂的时候,我们并不知道context是从哪里传过来的;而且context是一个全局变量,全局变量正是导致应用走向混乱的罪魁祸首.

使用context

下面例子中的组件关系: ListItem是List的子组件,List是app的子组件

ListItem.jsx

import React, { Component } from 'react';
import PropTypes from 'prop-types';
class ListItem extends Component {
 // 子组件声明自己要使用context
 static contextTypes = {
  color: PropTypes.string,
 }
 static propTypes = {
  value: PropTypes.string,
 }
 render() {
  const { value } = this.props;
  return (
   <li style={{ background: this.context.color }}>
    <span>{value}</span>
   </li>
  );
 }
}
export default ListItem;

List.jsx

import ListItem from './ListItem';
class List extends Component {
 // 父组件声明自己支持context
 static childContextTypes = {
  color: PropTypes.string,
 }
 static propTypes = {
  list: PropTypes.array,
 }
 // 提供一个函数,用来返回相应的context对象
 getChildContext() {
  return {
   color: 'red',
  };
 }
 render() {
  const { list } = this.props;
  return (
   <div>
    <ul>
     {
      list.map((entry, index) =>
       <ListItem key={`list-${index}`} value={entry.text} />,
      )
     }
    </ul>
   </div>
  );
 }
}
export default List;

app.jsx

import React, { Component } from 'react';
import List from './components/List';
const list = [
 {
  text: '题目一',
 },
 {
  text: '题目二',
 },
];
export default class App extends Component {
 render() {
  return (
   <div>
    <List
     list={list}
    />
   </div>
  );
 }
}

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

使用自定义事件机制

在componentDidMount事件中,如果组件挂载完成,再订阅事件;在组件卸载的时候,在componentWillUnmount事件中取消事件的订阅;

以常用的发布/订阅模式举例,借用Node.js Events模块的浏览器版实现

使用自定义事件的方式

下面例子中的组件关系: List1和List2没有任何嵌套关系,App是他们的父组件;

实现这样一个功能: 点击List2中的一个按钮,改变List1中的信息显示

首先需要项目中安装events 包:

npm install events --save

在src下新建一个util目录里面建一个events.js

import { EventEmitter } from 'events';
export default new EventEmitter();

list1.jsx

import React, { Component } from 'react';
import emitter from '../util/events';
class List extends Component {
 constructor(props) {
  super(props);
  this.state = {
   message: 'List1',
  };
 }
 componentDidMount() {
  // 组件装载完成以后声明一个自定义事件
  this.eventEmitter = emitter.addListener('changeMessage', (message) => {
   this.setState({
    message,
   });
  });
 }
 componentWillUnmount() {
  emitter.removeListener(this.eventEmitter);
 }
 render() {
  return (
   <div>
    {this.state.message}
   </div>
  );
 }
}
export default List;

List2.jsx

import React, { Component } from 'react';
import emitter from '../util/events';
class List2 extends Component {
 handleClick = (message) => {
  emitter.emit('changeMessage', message);
 };
 render() {
  return (
   <div>
    <button onClick={this.handleClick.bind(this, 'List2')}>点击我改变List1组件中显示信息</button>
   </div>
  );
 }
}

APP.jsx

import React, { Component } from 'react';
import List1 from './components/List1';
import List2 from './components/List2';
export default class App extends Component {
 render() {
  return (
   <div>
    <List1 />
    <List2 />
   </div>
  );
 }
}

自定义事件是典型的发布订阅模式,通过向事件对象上添加监听器和触发事件来实现组件之间的通信

总结

  • 父组件向子组件通信: props
  • 子组件向父组件通信: 回调函数/自定义事件
  • 跨级组件通信: 层层组件传递props/context
  • 没有嵌套关系组件之间的通信: 自定义事件

在进行组件通信的时候,主要看业务的具体需求,选择最合适的;

当业务逻辑复杂到一定程度,就可以考虑引入Mobx,Redux等状态管理工具

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

参考

  • reactjs官方文档
  • 深入React技术栈
  • React中组件间通信的几种方式
Javascript 相关文章推荐
实现局部遮罩与关闭原理及代码
Feb 04 Javascript
非html5实现js版弹球游戏示例代码
Sep 22 Javascript
jQuery aminate方法定位到页面具体位置
Dec 26 Javascript
js实现3D图片逐张轮播幻灯片特效代码分享
Sep 09 Javascript
工厂模式在JS中的实践
Jan 18 Javascript
JavaScript中重名的函数与对象示例详析
Sep 28 Javascript
用vue写一个仿简书的轮播图的示例代码
Mar 13 Javascript
基于JS实现带动画效果的流程进度条
Jun 01 Javascript
Element-ui中元素滚动时el-option超出元素区域的问题
May 30 Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 Javascript
JavaScript代码简化技巧实例解析
Sep 09 Javascript
element-ui封装一个Table模板组件的示例
Jan 04 Javascript
vue项目中v-model父子组件通信的实现详解
Dec 10 #Javascript
Angular项目从新建、打包到nginx部署全过程记录
Dec 09 #Javascript
利用ES6实现单例模式及其应用详解
Dec 09 #Javascript
利用node.js如何创建子进程详解
Dec 09 #Javascript
微信小程序使用slider设置数据值及switch开关组件功能【附源码下载】
Dec 09 #Javascript
微信小程序实现action-sheet弹出底部菜单功能【附源码下载】
Dec 09 #Javascript
微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】
Dec 09 #Javascript
You might like
phpcms模块开发之swfupload的使用介绍
2013/04/28 PHP
php 模拟POST提交的2种方法详解
2013/06/17 PHP
php的sso单点登录实现方法
2015/01/08 PHP
PHP对文件夹递归执行chmod命令的方法
2015/06/19 PHP
使用js声明数组,对象在jsp页面中(获得ajax得到json数据)
2013/11/05 Javascript
jQuery实现级联菜单效果(仿淘宝首页菜单动画)
2014/04/10 Javascript
jquery修改网页背景颜色通过css方法实现
2014/06/06 Javascript
基于jquery ui的alert,confirm方案(支持换肤)
2015/04/03 Javascript
JavaScript数组去重的3种方法和代码实例
2015/07/01 Javascript
javascript倒计时效果实现
2015/11/12 Javascript
第一次接触神奇的Bootstrap
2016/10/14 Javascript
JS获得一个对象的所有属性和方法实例
2017/02/21 Javascript
JavaScript箭头(arrow)函数详解
2017/06/04 Javascript
微信小程序日历组件calendar详解及实例
2017/06/08 Javascript
vue2项目使用sass的示例代码
2017/06/28 Javascript
node.js+captchapng+jsonwebtoken实现登录验证示例
2017/08/17 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
vue2.0 子组件改变props值,并向父组件传值的方法
2018/03/01 Javascript
详解Vue2.0组件的继承与扩展
2018/11/23 Javascript
Vue程序调试的方法
2019/06/17 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
JS数组扁平化、去重、排序操作实例详解
2020/02/24 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
2020/09/01 Javascript
python 循环遍历字典元素的简单方法
2016/09/11 Python
Python实现将罗马数字转换成普通阿拉伯数字的方法
2017/04/19 Python
Python scrapy增量爬取实例及实现过程解析
2019/12/24 Python
Pytorch模型转onnx模型实例
2020/01/15 Python
python实现引用其他路径包里面的模块
2020/03/09 Python
Stylenanda中文站:韩国一线网络服装品牌
2016/12/22 全球购物
美国专业消费电子及摄影器材网站:B&H Photo Video
2019/12/18 全球购物
妇女儿童发展规划实施方案
2014/03/16 职场文书
大学生入党自荐书
2015/03/05 职场文书
餐厅开业活动方案
2019/07/08 职场文书
网络新闻该怎么写?这些写作技巧你都知道吗?
2019/08/26 职场文书
pytorch加载预训练模型与自己模型不匹配的解决方案
2021/05/13 Python
python实现局部图像放大
2021/11/17 Python