前言
自 Redux 诞生起,一直都是 React 最热门的状态管理库之一。条理清晰的工作原理和简明易懂的源码逻辑,让它拥有非常不错的的稳定性和扩展性。直到现在,也只有同样十分优秀的 Mobx 能与其较量。
Redux 的缺陷
第一,Redux 的架构代码多且分散,对中小型项目来说,架构代码甚至能占到 Redux 代码的一半。在不熟悉用法的新人眼里,这些无关业务的代码十分影响开发逻辑,被人戏称为“十分钟从入门到劝退”。
第二,更新状态时,dispatch(action) -> reducer 的流程,让代码书写变得繁琐。而且,为了遵循“不可变状态”,每次更新状态时,都需要构造返回一个全新的对象。这个过程既繁琐,又容易在修改过程中发生错误。
第三,早期的 react-redux 库是通过全局刷新来重新渲染页面,性能全靠 React 的 diff 算法硬撑。好在后来推出了 Hook API,对 connect API 也进行了优化,让状态更新精准到了组件级别。这在 React16 上已经(基本)不需要考虑性能的问题了。
dream-redux 解决的问题
dream-redux 的出现,正是为了解决上面提到的前两个缺点:“搭建难”和“更新难”。
npm install --save dream-redux
轻松搭建
dream-redux 集成了 redux,react-redux,redux-persist,redux-thunk,redux-promise 等常规 Redux 开发套装,并且只需要“一个配置”和“两行代码”,就能完成众多 Redux 系列库的搭建。
// src/store/index.js
import { StoreCreator } from 'dream-redux'
// 【一个配置】
const config = {
reducerConfig: {
name: 'app',
initialState: { count: 0, list: [] }
}
}
// 【第一行代码】实例化并导出 store 和 APIs
export const {
store, // 核心对象,同 redux 的 store
useSelector, // 获取状态的 API,同 react-redux 的 useSelector
setReducer, // 极简的 dispatch API
commitMutation // 功能完善的 dispatch API
} = new StoreCreator(config)
// src/index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'dream-redux'
import { store } from './store/index.js'
import App from './App.jsx'
// 【第二行代码】使用 Provider 引入 store,包裹项目代码
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
)
轻松更新
dream-redux 凭借 immer 库强大的特性,让不可变状态可以被“直接”修改。而且,更新过程无需统一在 reducer 中处理,而是既可以在组件中直接修改,也可以合并到 action 中,形成一个类似 Vuex 的 Mutation 结构,在 mutation 对象中完成修改。
这样便无需再专门维护 reducer 函数,对用于匹配的 type 的严格要求也不再必须了,大大减少了机械编写的代码量。
import React from 'react'
import { useSelector, setReducer, commitMutation } from 'src/store/index.js'
export default function Example() {
// useSelector 用法和 react-redux 完全一样
const count = useSelector(state => state.count)
const list = useSelector(state => state.list)
function runSetReducer() {
// 最简单的修改方法,不建议在正式项目里使用
setReducer('app', state => {
state.count++
})
}
function runCommitMutation() {
// 正式项目中,一般会将多个 mutationCreator 统一写在一个单独的文件中
const mutationCreator = listItem => {
return { // 返回一个 mutation 对象
type: 'EXAMPLE_A',
target: 'app',
operation: state => {
state.list.push(listItem)
}
}
}
commitMutation(mutationCreator('This is an example text'))
}
return (
<div>
<div>{count}</div>
<div>
{list.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
<button onClick={runSetReducer}>SetReducer</button>
<button onClick={runCommitMutation}>CommitMutation</button>
</div>
)
}
可以看到,更新流程中,开发者只需要编写 mutationCreator,更新逻辑直接写在 mutation 中,使用时在组件里通过 commitMutation 调用即可。
以上就是 dream-redux 的入门介绍了,是不是非常的简洁!
dream-redux 对开发中普遍遇到的复杂场景和解决方案,都有对应的文档进行教学。可以 点击进入 GitHub 仓库 查阅详细文档。
兼容第三方库
dream-redux 内置了最常用的 redux-thunk,也实现了 redux-promise 的功能,未来还会继续整合优秀的中间件。如果开发者需要自行添加或编写中间件,比如 redux-saga,可以按照文档的格式传入中间件使用。
由于 dream-redux 实质上并没有修改 redux 和 react-redux,所以并不影响绝大部分中间件和第三方库的使用。如果有一些实用的库无法兼容,烦请在 Issue 中告知,我们会尽快整合或给出解决方案。
方便不同背景的开发者轻松上手
零基础者
对于从来没使用过 Redux,Mobx 或 Vuex 的开发者,dream-redux 应该是最适合上手的之一了。免去各种干扰,只需了解 reducer 和 mutation 的基本概念,就可以动手开发了。
了解过 Redux 和 Dva
dream-redux 类似于使用 thunk 而非 saga 处理异步,直接修改状态而非编写 switch-case 和构建新对象的 Dva。两者在不同方面有各自优势。如果更偏向 reducer 统一处理的写法,或者要搭配 umi 框架使用,请选择 Dva。
了解过 Vuex
对于使用过 Vuex 的开发者,那使用 dream-redux 时一定会十分熟悉,因为更新流程的代码结构就是借鉴了 Vuex 的 Mutation 和 Action,在单 reducer 模式下更新流程基本一致。
结束语
Redux 相比其他状态管理库,虽然入门比较难。但上手后,清晰的工作流程和强大灵活的中间件机制,让各种复杂度的开发都不至于出现不可预期的 bug。
并不复杂的 redux 和 react-redux 源码,也方便开发者精通底层原理,这也间接促成了社区生态的繁荣。(react-redux 的源码客观上还是有些难的,但比起同级别的其他库,已经算是很良心了。)
而 dream-redux 就是专门为了降低 Redux 使用门槛而生的。
希望这个项目,能帮助曾经或即将入门 Redux 被劝退的童鞋,重新看待这个经典的宝藏框架;也能帮助已经上手,却被繁琐操作困扰的朋友,代码能敲得更加顺畅。
之后可能还会写一些有关 Redux 的源码文章,简明扼要地分析一下 Redux 系列的核心流程和 dream-redux 的一些开发思路,让大家不再畏惧这个又爱又恨的前端精品。
也希望大家能不吝支持一下,给 dream-redux 来个 star,给予我更多开发和创作的动力,在此谢过!
链接1:dream-redux GitHub 地址,内有详细文档说明。
链接2:结合 dream-redux 和 typescript 开发的开源 CMS 项目 lin-cms-react,可查看在实际项目中的架构和使用情况。