React 组件间的通信
在 React 里, UI = render(state)
,页面是由数据驱动更新的。平时我们写 React 的时候,本质上就是在跟数据打交道,了解清楚数据的流向,对厘清业务是有帮助的。而 React 在数据这方面,推崇的是 单向数据流
,也就是数据只能由高层级的组件流向低层级的组件。下面介绍几种 React 组件间的数据通信。
父子组件
对于父子组件来说,通常是由父组件定义数据,然后通过 props
传递给子组件。在这种模式下,子组件就是个 无状态组件
,它的数据全部由父组件定义和控制。当需要更改自身状态时,通过 事件驱动
的方式来更改,即子组件 emit 发送一个事件出去,并把当前的数据状态传递给父组件,父组件接收到后,调用 setState
更新数据,然后页面 UI 随之刷新。
兄弟组件
对于兄弟组件,数据的传递方式是通过 父组件
做中转。假设有兄弟组件 B 和 C,以及它们的父组件 A。此时 B 要向 C 传递数据,怎么做呢?首先,父组件 A 在子组件 B 里绑定一个事件监听函数 fn,子组件 B 通过 fn 函数入参把想传递的数据交给父组件 A,A 拿到数据后,通过 setState
更改 A 组件当前的 state 数据,然后再把这个数据通过 props
的方式传递给子组件 C。这样就实现了兄弟组件通信。
跨组件通信 —— 发布订阅模式
React 单向数据流的好处是数据来源清晰,方便管理,但坏处是假设组件很多的话,通过一层层 props 传递下去, 嵌套太多不是好办法
。所以还有一种传递数据的方式: 发布——订阅模式
。它通过一方发布事件,另一方订阅事件来实现数据的传递。对于发布订阅模式来说,有以下几个重要方法:
on
off
emit
once
一个简易的发布——订阅模式实现代码如下:
class EventEmitter {
constructor() {
this.events = {}
}
emit(type, ...args) {
this.events[type].forEach(fn => {
fn(...args)
})
return true
}
on(type, handler) {
this.events[type] = this.events[type] || []
this.events[type].push(handler)
return this
}
off(type, handler) {
const lis = this.events[type]
if (!lis) return this
for (let i = lis.length; i > 0; i--) {
if (lis[i] === handler) {
lis.splice(i, 1)
break
}
}
return this
}
once(type, handler) {
this.events[type] = this.events[type] || []
const onceWrapper = () => {
handler()
this.off(type, onceWrapper)
}
this.events[type].push(onceWrapper)
return this
}
}
Context API
React 本身提供了一个组件间全局通信的方式,那就是 Context
API。这个 API 有三个重要概念:
React.createContext
: 创建一个上下文对象用来保存数据Provider
:把组件包裹在 Provider 里,通过 Provider 的 value 属性获取需要传递的数据Consumer
: 消费数据的组件,接收定义在 Provider 的 value 数据
Context API
驾驭起来难度大,因此很少被推荐使用,如果是大型复杂项目,数据管理通常会采用第三方状态库 redux
redux
引用官方的描述:
Redux 是 JavaScript 状态容器,它提供可预测的状态管理。
Redux 并不属于 React,而是提出了一套数据管理的思想和规范,React 根据这个思想实现了自己的状态管理库 react-redux
。
对于 Redux 架构,有三个重要概念需要理解:
store
: 全局唯一的数据源,它是只读的reducer
:是一个纯函数,它根据 action 的动作,来对数据进行分发处理,最后返回新的数据状态,更新 store。store 一旦更新,就驱动视图层刷新,UI 也就改变了,这是个严格的单一数据流
action
: 因为 store 是只读的,我们如果想改变数据,就需要定义一个改变「动作」,这个动作描述了新的数据状态信息,它会被 reducer 接收处理。
redux 的工作流是这样:首先,我们需要有一个类似 createStore
的方法来创建我们的唯一数据源 store
,有了 store 后,我们想改变数据,该怎么做?首先,我们需要定义一个 action 动作,描述你这个数据是新增还是修改,比如 action = {type: 'ADD', payload: '张三'}
,定义 action 就是解决 你想要什么
。
然后,我们还要编写 reducer
纯函数,在里面指定如何来响应 action
,比如上面的 action 是新增一个叫 张三
的名字,那我们就要在函数里根据这个动作,来创建新的数据,这个数据最终会被处理更新到 store 上。现在我们 store 有了,action 也有了,reducer 处理函数也有了,那怎么实现更新到 store 这个操作呢?
这时 dispatch
函数就登场了,当你通过 createStore
方法创建完 store 数据源后,就可以通过 store.dispatch
来触发数据的更新。
总结下 redux 的整个工作流程:
- 创建唯一数据源 store
- 定义更改数据的动作 action
- 定义处理 action 的函数,称作 reducer
- 通过
store.dispatch
来让 reducer 处理 action
总结
React 遵循单向数据流原则,有以下几种传递数据的方式:
props
发布——订阅模式
Context API
redux
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论