难道如今状态管理不是一个能够解决的问题吗?直观地说,开发人员彷佛知道一个隐藏的事实:状态管理的使用彷佛比须要的更困难。在本文中,咱们将探讨一些你可能一直在问本身的问题:javascript
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!前端
做为前端开发人员,不只仅是布局,开发的真正艺术之一是知道如何管理存储状态。简而言之:状态管理是复杂的,但又并不是那么复杂。java
让咱们看看使用React等基于组件的视图框架/库时的选项:react
存在于单个组件内部的状态。在React中,经过setState
方法更新state
。git
从父级传递给子级的状态。在React中,将 props
做为属性传递给子组件。github
状态保存在根 provider (提供者) 组件中,并由 consumer (消费者) 在组件树的某个地方访问,而不考虑组件之间的层级关系。在 React 中,经过 context API
能够实现。编程
大多数的状态都是存在于视图中的,由于它是用来反映用户界面的。那么,对于反映底层数据和逻辑的其它状态,又属于谁呢?redux
将全部内容都放在视图中可能会致使关注点的分离:它将与javascript视图库联系在一块儿,使代码更难测试,并且可能最大的麻烦是:必须不断地思考和调整存储状态的位置。segmentfault
状态管理因为设计变动而变得复杂,并且一般很难判断哪些组件须要哪些状态。最直接的选择是从根组件提供全部状态,若是真要这么作的话,那么选用下一种方式会更好。数组
状态能够移出视图库。而后,库可使用提供者/消费者模式链接以保持同步。
也许最流行的状态管理库是Redux。在过去的两年里,它变得愈来愈受欢迎。那么为何这么喜欢一个简单的库呢?
Redux 更具性能?答案是否认的。事实上,为了每个必须处理的新动做(action),都会稍微慢一些。
Redux是否更简单?固然不是。
简单应当是纯javascript:好比 TJ Holowaychuk 在twitter上说
那么为何不是每一个人都使用 global.state={}?
在表层之下,Redux 与 TJ 的根对象{}
彻底相同——只是包装在了一系列实用工具的管道(pipeline)中。
在 Redux 中,不能直接修改状态。只有一种方法:派发(Dispatch)一个动做(Action)到管道中,管道会自动根据动做去更新状态。
沿着管道有两组侦听器:中间件(middleware)和订阅(subscriptions)。 中间件是能够侦听传入的动做的函数,支持诸如“logger”,“devtools”或“syncWithServer”侦听器之类的工具。 订阅是用于广播这些状态更改的函数。
最后,合成器(Reducer)函数负责把状态变动拆分红更小、更模块化、更容易管理的代码块。
和使用一个全局对象相比,Redux 确实简化了开发过程。
将 Redux 视为一个带有更新前/更新后钩子的全局对象,以及可以以简单的方式合成新状态。
是的。有几个不能否认的迹象代表 API 须要改进,这些能够用下面的方程来总结
time_saved来表示你开发本身的解决方案所花费的时间,time_invested
至关于阅读文档,学习教程和研究不熟悉的概念所花费的时间。
Redux 是一个拥有陡峭学习曲线的小型库。虽然有很多开发者可以克服深刻学习函数式编程的困难并从 Redux 获益良多,可是也有不少开发者望而却步,宁愿从新使用 jQuery。
使用jQuery你不须要理解“monad”是什么,你也不须要为了使用Redux去理解函数组合。
使用 jQuery 你不须要理解“comonad”是什么,你也不须要为了使用 Redux 去理解函数组合。
任何框架或者库的目的都应该是把复杂的事物抽象得更加简单。
我认为Redux值得重写,至少有如下 6 个方面能够改进得更友好。
让咱们来看看一个基本的 Redux 初始化过程,以下图左边所示:
许多开发人员在第一步后就在这里暂停,茫然地盯着深渊。 什么是 thunk?compose?一个函数能作到这些吗?
若是 Redux 是基于配置而不是函数组合的话,那么像右边那样的初始化过程明显看起来更加合理。
Redux 中的 reducers 能够经过一个转换,让咱们远离已经习惯但没必要要且冗长的 switch 语句。
假设reducer
与action
类型匹配,那么咱们能够对参数进行反转,这样每一个reducer都是一个接受state
和action
的纯函数。 也许更简单,咱们能够标准化action
并仅传入state
和有效负载(payload)。
thunk
一般用于在 Redux 中建立异步 action。 在许多方面,thunk 的工做方式看起来更像是一个聪明的黑客,而不是官方推荐的解决方案。 咱们一步一步来看:
怎么会这样?一个简单的 action 究竟是做为一个动态类型的对象、一个函数,仍是一个 Promise?这难道不是一种拙劣的实践吗?
如上图右边所示,难道咱们就不能只使用 async/await ?
仔细想一想,其实有两种 action
1.reducer action: 触发 reducer 并改变状态。
2.effect action:触发异步 action,这可能会调用reducer操做,但异步函数不会直接更改任何状态。
将这两种类型的 action 区分开来,将比上面的thunk用法更有帮助,也更容易理解。
为何咱们的标准实践要把 action creator 和 reducer 区分开来呢?可否只用其中一个呢?改变其中一个又是否会影响到另外一个?
action creator 和 reducer 是同一枚硬币的两面。
const ACTION_ONE = 'ACTION_ONE'是分离 action creators 和 reducers 的一个冗余产物。应将二者视为一体,而且再也不须要文件导出类型的字符串。
按照使用方式,把 Redux 中所涉及的概念进行合并分组,那么咱们能够得出下面这个更简单的模式。
能够从 reducer 中自动肯定 action creator。 毕竟,在这种状况下,reducer 能够成为action creator。
使用一个基本的命名约定,下面是可预测的:
reducer
命名为 increment,那么 type
就是 increment。更好的作法是加上命名空间 “count/increment”。如今,从 count.increment
中,咱们能够以一个 reducer 生成 action creator。
以上这些痛点就是咱们建立 Rematch 的缘由。
Rematch 对 Redux 进行了封装,提供更简单的 API,但又不失任何可配置性的特色
请参见下面的一个完整的 Rematch 示例:
在过去的几个月里,我一直在实际业务中使用 Rematch。做为证实,我会说:状态管理从未变得如此简单、高效。
Redux 是一个出色的状态管理工具,有键全的中间件生态与出色的开发工具。
Rematch 在 Redux 的基础上构建并减小了样板代码和执行了一些最佳实践。
说得清楚点,Rematch 移除了 Redux 所须要的这些东西:
让 Redux 与Rematch 做对比有助于让理解更加清晰。
1.model
import { init } from '@rematch/core' const count = { state: 0, reducers: { upBy: (state, payload) => state + payload } } init({ model: { count } })
2.View
import { connect } from 'react-redux' // Component const mapStateToProps = (state) => ({ count: state.count }) const mapDispatchToProps = (dispatch) => ({ countUpBy: dispatch.count.upBy }) connect(mapStateToProps, mapDispatchToProps)(Component)
1.store
import { createStore, combineReducers } from 'redux' // devtools, reducers, middleware, etc. export default createStore(reducers, initialState, enhancers)
2.Action Type
export const COUNT_UP_BY = 'COUNT_UP_BY'
3.Action Creator
import { COUNT_UP_BY } from '../types/counter' export const countUpBy = (value) => ({ type: COUNT_UP_BY, payload: value, })
4.Reducer
import { COUNT_UP_BY } from '../types/counter' const initialState = 0 export default (state = initialState, action) => { switch (action.type) { case COUNT_UP_BY: return state + action.payload default: return state } }
5.view
import { countUpBy } from '../actions/count' import { connect } from 'react-redux' // Component const mapStateToProps = (state) => ({ count: state.count, }) connect(mapStateToProps, { countUpBy })(Component)
Redux 并无被抛弃,并且也不该该被抛弃。
只是,咱们应该以更低的学习成本,更少的样板代码和更少的认知成本,来拥抱 Redux 背后的简单哲学。
你的点赞是我持续分享好东西的动力,欢迎点赞!