前言
上一章节我们一起学习了通过SDK的设计,了解了 SDK 设计中的事件监听模型,同样 EventEmitter
也可以作为中介者模型来实现组件之间的跨级通信。
本章节我们就一起来学习几种通用的组件通信模型, 同时通过中介者模型实现组件元素之间跨级通信。
开箱即用的源码
源码地址:https://github.com/dkypooh/front-end-develop-demo/tree/master/base/babel7-react
组件通信模式
本小节以 React
组件框架为例,和大家一起探讨学习几种通用的组件通信模型。
- 父组件到子组件:
props
属性 ,instance methods
实例方法 - 子组件到父组件:
callback
回调方法,event bubbles
事件冒泡 - 临近兄弟节点:
Parent Component
父组件 - 任何节点:
Observer Pattern
观察者模式,Global Variables
全局变量,Context
React执行上下文
父组件到子组件
Props
Props
是一个父节点到一个子节点通信最常见的方式。
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
ReactDOM.render(
<Welcome name="Sara" />,
document.getElementById('root')
);
Instance Methods
父组件可以使用refs调用子组件上的实例方法
class TheChild extends React.Component {
myFunc() {
return "hello";
}
}
class TheParent extends React.Component {
render() {
return (
<TheChild
ref={foo => {
this.foo = foo;
}}
/>
);
}
componentDidMount() {
var x = this.foo.myFunc();
// x is now 'hello'
}
}
子组件到父组件
Callback Functions
最简单的方法是父组件将函数传递给子组件,子组件调用父组件的方法
以属性的方式传递函数
<MyChild myFunc={this.handleChildFunc} />
子组件调用方式
this.props.myFunc();
添加属性函数声明
MyChild.propTypes = {
myFunc: React.PropTypes.func
};
Event Bubbling
事件冒泡不是 React
的概念,它是DOM元素的概念,它可以像回调函数一样通过冒泡方式把数据通子组件发送到父组件。
class ParentComponent extends React.Component {
render() {
return (
<div onKeyUp={this.handleKeyUp}>
// Any number of child components can be added here.
</div>
);
}
handleKeyUp = (event) => {
// This function will be called for the 'onkeyup'
// event in any <input/> fields rendered by any of
// my child components.
}
}
临近兄弟节点
父组件通信
如果两个相邻组件需要通信, 我们可以找到他们相邻的父节点进行中转通信
class ParentComponent extends React.Component {
render() {
return (
<div>
<SiblingA
myProp={this.state.propA}
myFunc={this.siblingAFunc}
/>
<SiblingB
myProp={this.state.propB}
myFunc={this.siblingBFunc}
/>
</div>
);
}
// Define 'siblingAFunc' and 'siblingBFunc' here
}
任何节点
全局变量
组件中都可以引用到全局变量,一般可以挂载到 window
对象上面,切记不要滥用他们
window.x = 'global variable'
Context
Context
使用类似于 Props
, 和 Props
区别在于它可以提供整个树形组件的数据(多级子组件), Context
只能向下数据传递(父组件到子组件),可以配合 callback functions
一起使用(子组件到父组件)。
使用 Props
实例
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
使用 Context
实例
// 创建 Context 实例
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
return (
// 提供 `Provider` 上下文容器
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {d
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
中介者模式通信
本小节和大家一起探讨学习,通过中介者模式实现组件元素之间跨级通信。同理 Redux
状态管理也是采用中介者模式实现 数据状态扁平化管理
不需要考虑A,B,C组件的树形关系,这样就可以实现扁平化通信,如图:A组件的行为就可以被B和C组件响应。
EventBus实现
EventBus
模块实现引用的是通用SDK的 event
模块。实现事件发布和监听管理。 代码可以参考上一章节(设计模式 - EventEmitter实现)
EventBus源码地址
源码地址:https://github.com/dkypooh/front-end-develop-demo/tree/master/base/babel7-react/src/common/eventBus
组件通信实例
不通过父子组件属性和回调函数通信, 通过 EventBus
中介者模式实现一个加减计数器组件。
目录结构
├── src
│ ├── common
│ │ ├── event.js
│ │ └── eventBus
│ │ ├── event.d.ts
│ │ ├── event.js
│ │ └── event.ts
│ ├── components
│ │ ├── add
│ │ │ └── index.jsx
│ │ └── show
│ │ └── index.jsx
│ └── index.jsx
Add 组件
import React from "react";
import event from '../../common/event';
export default class extends React.PureComponent {
handleAdd() {
// 触发加号事件
event.emit('add');
}
handleReduce() {
// 触发减号事件
event.emit('reduce');
}
render() {
return (
<div className="m-opt">
<div onClick={() => {this.handleAdd()}}>+</div>
<div onClick={() => {this.handleReduce()}}>-</div>
</div>
);
}
}
Show 组件
import React from "react";
import event from '../../common/event';
export default class extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
number: 0
};
// 监听减号事件,并把 `number` 字段减一
event.on('reduce', () => {
this.setState({
number: this.state.number - 1
});
});
// 监听加号事件,并把 `number` 字段加一
event.on('add', () => {
this.setState({
number: this.state.number + 1
});
});
}
render() {
return (
<div className="m-show">
{this.state.number}
</div>
);
}
}
Add组件
出发操作加减的事件, Show组件
监听事件实现状态更改
结语
这样介绍了组件通信常用的几种方式,以及通过 EventBus
实现组件之间扁平化通信。 本章以 React
框架举例,同时在其他主流的 MVVM
框架都适用(Vuejs,Angular等)。