lizhiyong 2019-06-27
欢迎关注我的公众号睿Talk
,获取我最新的文章:
Redux 作为 React 全家桶的一名重要成员,在众多大牛的力荐之下得到了广泛的应用,Github 上的 Star 也达到 42k 之多!然而,当触及最根本的问题,为什么要使用 Redux 的时候,很多人是说不清楚的。本文尝试解读 Redux 的设计初衷,并结合 React 谈谈实际的使用场景。本文只谈理论,不会对 Redux 的使用作过多的介绍。
如何用一句话来描述 Redux ?官网是这么写的:
Redux is a predictable state container for JavaScript apps.
Redux是一个为JavaScript应用设计的,可预测的状态容器。
由此可见,Redux的主要作用是管理程序状态的。这里所说的状态指的是数据状态,也就model的状态( state )。当今流行的前端框架,都是使用 MVVM 的设计模式,也就 Model,View,View-Model。框架承担了大部分 View-Model 的工作,我们只需要把 Model 和 View 的映射关系定义清楚就行。用公式描述就是View = Render(Model)
。所以本质来说,用户看到的页面,是Model 在某个状态下的视觉呈现。
页面的切换,可以简单理解为 Model 的状态变迁(同时也会涉及到 UI 的状态变迁)。数据的状态和 UI 的状态,下文统一称为 state。
那么,为什么需要专门有一个工具来管理 state 呢?先来看看下面这张图:
这是一张backbone的数据流图,一个 View 可能涉及到多个 Model,当用户操作 View 的时候,可能引发多个 Model 的更新,而 Model 的更新又会引发另一个 View 的改变。View 与 Model 之间的关系错综复杂,如果想要添加一个功能或者修改 bug,都要花大量的时间进行调试,还容易出问题。
你也许会说,使用 React 就不会遇到这种问题,因为 React 天然就是使用 state 来管理界面的展示,state 与 View 一一对应,这与 Redux 的思想是契合的。然而,随着应用复杂度的增加,你会经历以下心路历程:
共享的state需要放在最顶层维护,然后一层一层地往下传递修改state的方法和展现的数据。这时你会发现,很多数据中间层的组件根本不需要用到,但由于子组件需要用,不得不经过这些中间层组件的传递。更令人头疼的事,当state变化的时候,你根本分不清楚是由哪个组件触发的。
应用的state统一放在store里面维护,当需要修改state的时候,dispatch一个action给reducer,reducer算出新的state后,再将state发布给事先订阅的组件。
所有对状态的改变都需要dispatch一个action,通过追踪action,就能得出state的变化过程。整个数据流都是单向的,可检测的,可预测的。当然,另一个额外的好处是不再需要一层一层的传递props了,因为Redux内置了一个发布订阅模块。
Redux虽好,但并不适用于所有项目。使用Redux需要创建很多模版代码,会让 state 的更新变得非常繁琐,谁用谁知道
正如 Redux 的作者 Dan Abramov 所言,Redux 提供了一个交换方案,它要求应用牺牲一定的灵活性以达到以下三个要求:
- 通过简单对象和数组描述应用状态
- 通过简单对象描述应用状态的改变
- 使用纯函数来描述状态改变的逻辑
相应的,你会得到以下好处:
- 可以很方便的将 state 存储到 Local Storage 中并在需要的时候取出并启动应用
- 可以在服务器端直接计算出 state 再存到 HTML 中,然后在客户端秒开页面
- 方便的序列化用户操作和对应的 state 快照,在出现 bug 的时候可以利用这些信息快速复现问题
- 通过在网络中传递 action 对象,可以在对代码进行很小改动的情况下实现分布式应用
- 可以在对代码进行很小改动的情况下实现撤销和恢复功能
- 在开发过程中可以任意跳转到应用的某个历史状态并进行操作
- 提供全面的审查和控制功能,让开发者可以定制自己的开发工具
- 将 UI 和业务逻辑分离,使业务逻辑可以在多个地方重用
另外,对于 React 来说,当遇到以下情况你或许需要 Redux 的帮助:
Redux 是一个为 JavaScript 应用设计的,可预测的状态容器。在使用之前,最好先弄清楚他能为你的程序带来什么,需要你做出怎样的妥协,也就是上文提到的交换方案。希望读完本文后,你对Redux 的设计思想与使用场景有一个更全面的了解。