单向数据流
当前组件的 state 以 props 的形式流动时,只能流向组件树中比自己层级更低的组件,父-子通信、子-父通信和兄弟组件通信。
“发布-订阅”模式驱动数据流
使用发布-订阅模式的优点在于:监听事件的位置和触发事件的位置是不受限的,就算相隔十万八千里,只要它们在同一个上下文里,就能够彼此感知
事件的监听(订阅)和事件的触发
on():负责注册事件的监听器,指定事件触发时的回调函数
emit():负责触发事件,可以通过传参使其在触发的时候携带数据
off():负责监听器的删除
// 注意这个 myEvent 是提前实例化并挂载到全局的,此处不再重复示范实例化过程
window.myEvent = new myEventEmitter()
B组件
const globalEvent = window.myEvent
class B extends React.Component {
// 这里省略掉其他业务逻辑
state = {
newParams: ""
};
handler = (params) => {
this.setState({
newParams: params
});
};
bindHandler = () => {
globalEvent.on("someEvent", this.handler);
};
render() {
return (
<div>
<button onClick={this.bindHandler}>点我监听A的动作</button>
<div>A传入的内容是[{this.state.newParams}]</div>
</div>
);
}
}
A组件
class A extends React.Component {
// 这里省略掉其他业务逻辑
state = {
infoToB: "哈哈哈哈我来自A"
};
reportToB = () => {
// 这里的 infoToB 表示 A 自身状态中需要让 B 感知的那部分数据
globalEvent.emit("someEvent", this.state.infoToB);
};
render() {
return <button onClick={this.reportToB}>点我把state传递给B</button>;
}
}
全局通信方式Context
const AppContext = React.createContext(defaultValue)
const { Provider, Consumer } = AppContext
<Provider value={title: this.state.title, content: this.state.content}>
<Title />
<Content />
</Provider>
<Consumer>
{value => <div>{value.title}</div>}
</Consumer>
第三方数据流框架“课代表”: Redux
Redux 是一个状态容器,存放公共数据的仓库,在 Redux 的整个工作过程中,数据流是严格单向的
Redux 主要由三部分组成:store、reducer 和 action
store 就好比组件群里的“群文件”,它是一个单一的数据源,而且是只读的;
action 人如其名,是“动作”的意思,它是对变化的描述
reducer 是一个函数,它负责对变化进行分发和处理
如果你想对数据进行修改,只有一种途径:派发 action(派发 action,靠的是 dispatch)。action 会被 reducer 读取,进而根据 action 内容的不同对数据进行修改、生成新的 state(状态),这个新的 state 会更新到 store 对象里,进而驱动视图层面做出对应的改变
对于组件来说,任何组件都可以通过约定的方式从 store 读取到全局的状态,任何组件也都可以通过合理地派发 action 来修改全局的状态。Redux 通过提供一个统一的状态容器,使得数据能够自由而有序地在任意组件之间穿梭,这就是 Redux 实现组件间通信的思路