岂非如今状况治理不是一个可以处置惩罚的题目吗?直观地说,开辟人员好像晓得一个隐蔽的现实:状况治理的运用好像比须要的更难题。在本文中,我们将讨论一些你可以一直在问本身的题目:
- 你是不是须要一个用于状况治理的库?
- Redux 的受迎接水平是不是值得我们去运用? 为何或许为何不值得?
- 我们可否制订更好状况治理处置惩罚方案吗?假如能,要怎么做?
想浏览更多优良文章请猛戳GitHub博客,一年百来篇优良文章等着你!
状况治理须要一个库吗
作为前端开辟人员,不仅仅是规划,开辟的真正艺术之一是晓得怎样治理存储状况。简而言之:状况治理是庞杂的,但又并不是那末庞杂。
让我们看看运用React等基于组件的视图框架/库时的选项:
1. Component State (组件状况)
存在于单个组件内部的状况。在React中,经由历程setState
要领更新state
。
2. Relative State (关联状况)
从父级通报给子级的状况。在React中,将 props
作为属性通报给子组件。
3. Provided State (供应状况)
状况保存在根 provider (供应者) 组件中,并由 consumer (消费者) 在组件树的某个处所接见,而不斟酌组件之间的层级关联。在 React 中,经由历程 context API
可以完成。
大多数的状况都是存在于视图中的,因为它是用来反应用户界面的。那末,关于反应底层数据和逻辑的别的状况,又属于谁呢?
将一切内容都放在视图中可以会致使关注点的星散:它将与javascript视图库联络在一起,使代码更难测试,而且可以最大的贫苦是:必需不断地思索和调解存储状况的位置。
状况治理因为设想变动而变得庞杂,而且一般很难推断哪些组件须要哪些状况。最直接的挑选是从根组件供应一切状况,假如真要这么做的话,那末选用下一种体式格局会更好。
4. External State (外部状况)
状况可以移出视图库。然后,库可以运用供应者/消费者形式衔接以坚持同步。
或许最盛行的状况治理库是Redux。在过去的两年里,它变得愈来愈受迎接。那末为何这么喜好一个简朴的库呢?
Redux 更具机能?答案是不是定的。现实上,为了每一个必需处置惩罚的新行动(action),都邑轻微慢一些。
Redux是不是更简朴?固然不是。
简朴应当是纯javascript:比方 TJ Holowaychuk 在twitter上说
那末为何不是每一个人都运用 global.state={}?
为何运用 Redux
在表层之下,Redux 与 TJ 的根对象{}
完全相同——只是包装在了一系列实用东西的管道(pipeline)中。
在 Redux 中,不能直接修正状况。只要一种要领:派发(Dispatch)一个行动(Action)到管道中,管道会自动依据行动去更新状况。
沿着管道有两组侦听器:中间件(middleware)和定阅(subscriptions)。 中间件是可以侦听传入的行动的函数,支撑诸如“logger”,“devtools”或“syncWithServer”侦听器之类的东西。 定阅是用于播送这些状况变动的函数。
末了,合成器(Reducer)函数担任把状况变动拆分红更小、更模块化、更轻易治理的代码块。
和运用一个全局对象比拟,Redux 确切简化了开辟历程。
将 Redux 视为一个带有更新前/更新后钩子的全局对象,以及可以以简朴的体式格局合成新状况。
Redux 是不是是太庞杂了?
是的。有几个不可否认的迹象表明 API 须要革新,这些可以用下面的方程来总结
time_saved来示意你开辟本身的处置惩罚方案所消费的时候,time_invested
相当于浏览文档,进修教程和研讨不熟悉的观点所消费的时候。
Redux 是一个具有峻峭进修曲线的小型库。虽然有不少开辟者可以战胜深切进修函数式编程的难题并从 Redux 获益很多,然则也有很多开辟者望而生畏,情愿从新运用 jQuery。
运用jQuery你不须要明白“monad”是什么,你也不须要为了运用Redux去明白函数组合。
运用 jQuery 你不须要明白“comonad”是什么,你也不须要为了运用 Redux 去明白函数组合。
任何框架或许库的目标都应该是把庞杂的事物笼统得越发简朴。
从新设想Redux
我以为Redux值得重写,至少有以下 6 个方面可以革新得更友爱。
1.初始化
让我们来看看一个基础的 Redux 初始化历程,以下图左侧所示:
很多开辟人员在第一步后就在这里停息,茫然地盯着深渊。 什么是 thunk?compose?一个函数能做到这些吗?
假如 Redux 是基于设置而不是函数组合的话,那末像右侧那样的初始化历程显著看起来越发合理。
2. 简化 reducers
Redux 中的 reducers 可以经由历程一个转换,让我们阔别已习气但不必要且冗杂的 switch 语句。
假定reducer
与action
范例婚配,那末我们可以对参数举行反转,如许每一个reducer都是一个接收state
和action
的纯函数。 或许更简朴,我们可以规范化action
并仅传入state
和有用负载(payload)。
3.运用 Async/Await 替代 Thunks
thunk
一般用于在 Redux 中建立异步 action。 在很多方面,thunk 的工作体式格局看起来更像是一个智慧的黑客,而不是官方引荐的处置惩罚方案。 我们一步一步来看:
- 你派发一个action(dispatch an action),它现实上是一个函数而不是预期的对象。
- thunk 中间件搜检每一个行动,看看它是不是是一个函数。
- 假如是,中间件挪用该函数,并传入一些 store 的要领:dispatch 和 getState。
怎么会如许?一个简朴的 action 究竟是作为一个动态范例的对象、一个函数,照样一个 Promise?这岂非不是一种低劣的实践吗?
如上图右侧所示,岂非我们就不能只运用 async/await ?
4. 两种 action
细致想一想,其实有两种 action
1.reducer action: 触发 reducer 并转变状况。
2.effect action:触发异步 action,这可以会挪用reducer操纵,但异步函数不会直接变动任何状况。
将这两种范例的 action 辨别开来,将比上面的thunk用法更有协助,也更轻易明白。
5. 不再有 action 范例(action.type)变量
为何我们的规范实践要把 action creator 和 reducer 辨别开来呢?可否只用个中一个呢?转变个中一个又是不是会影响到另一个?
action creator 和 reducer 是统一枚硬币的两面。
const ACTION_ONE = ‘ACTION_ONE’是星散 action creators 和 reducers 的一个冗余产品。应将二者视为一体,而且不再须要文件导出范例的字符串。
6.reducers 即 action creators
根据运用体式格局,把 Redux 中所触及的观点举行兼并分组,那末我们可以得出下面这个更简朴的形式。
可以从 reducer 中自动肯定 action creator。 毕竟,在这类情况下,reducer 可以成为action creator。
运用一个基础的定名商定,下面是可展望的:
- 假如
reducer
定名为 increment,那末type
就是 increment。更好的做法是加上定名空间 “count/increment”。 - 每一个 action 都经由历程 payload 键来通报数据。
如今,从 count.increment
中,我们可以以一个 reducer 天生 action creator。
好消息:我们可以有一个更好的 Redux
以上这些痛点就是我们建立 Rematch 的缘由。
Rematch 对 Redux 举行了封装,供应更简朴的 API,但又不失任何可设置性的特性
请拜见下面的一个完全的 Rematch 示例:
在过去的几个月里,我一直在现实营业中运用 Rematch。作为证实,我会说:状况治理从未变得云云简朴、高效。
Redux 与 Rematch 的对照
Redux 是一个精彩的状况治理东西,有键全的中间件生态与精彩的开辟东西。
Rematch 在 Redux 的基础上构建并减少了榜样代码和执行了一些最好实践。
说得清楚点,Rematch 移除了 Redux 所须要的这些东西:
- 声明 action 范例
- action 建立函数
- thunks
- store 设置
- mapDispatchToProps
- sagas
让 Redux 与Rematch 作对照有助于让明白越发清楚。
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)
Redux (最好实践)
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)
Rudex 与 Rematch 的分数板
Redux 并没有被扬弃,而且也不该该被扬弃。
只是,我们应该以更低的进修本钱,更少的榜样代码和更少的认知本钱,来拥抱 Redux 背地的简朴哲学。
你的点赞是我延续分享好东西的动力,迎接点赞!