rematch一个redux框架,更是一个效率框架
从这个定义中可以直观的了解到,rematch这个框架是基于redux而建的。
就如rematch的作者所说,其创造的目的就是为了简化在使用redux的过程中所产生开发效率问题。其先驱有知名的dva框架,也是为了解决这个问题,但是rematch更加青出于蓝。
Redux的问题
redux已经提供了一个非常有建设性的理念,redux本身的实现也是简洁的,无可挑剔的,但是它为人诟病的就是需要写许多的重复的样板代码。下图是redux的工作流程:
所有的具体代码逻辑,都是通过dispatch来调用不同的action,然后触发对应的同步、异步逻辑。redux本身提供的同步逻辑(reducer)的方法,而异步的逻辑通常需要通过使用middleware来实现,比如使用社区的redux-thunk,redux-saga等等库。
这个简单的模型,带来了巨大的开发负担,来来回回需要写许多的样板代码,让开发者苦不堪言,下面来看个简单的例子:
// 0.定义状态
const state = {
hello: 'xx'
}
// 1.定义一个唯一的字符串来标识一个action,action之后是代表了所有触发的同步、异步逻辑
const testConstant = 'action1';
// 2.定义action
const testAction = (payload) => ({ type: testConstant, payload })
// 3.定义reducer
const testReducer = (state, action) => {
switch(action.type) {
case testConstant:
return {...state, ...action.payload}
}
return state;
}
// 4.触发action
dispatch(testAction({ hello: 'world!' }))
dispatch({ type: testConstant, payload: { hello: 'world' }})
上述例子看似简单,但是随着代码量的变大,大量的action出现,需要人工手动的声明每个,不同reducer分散,这时带来了两个问题:
1.记忆上的难度,因为所有的action是通过一个字符串来唯一标识的,那么随着action月来越多,记不住了😿
2.定义action、reducer的样板代码,每次都需要写,有的时候写在不同的文件中,切换的成本比较高
这个也是redux被人诟病,不适合小型项目,因为引入redux所带来的效率下降是一种规模效应,只有在项目比较大的时候,redux的好处才会大于带来的开发效率成本的下降
Redux框架
为了解决上述Redux出现的问题,社区出现许多的方案来解决
1.通过更高的管理方式,比如duck模式,这个方式只是把action、reducer通过一种整个的方式在物理上归类统一管理。或者通过自动代码生成的方式来解决手动书写的问题。
2.通过在redux上面再封装一层,把这种复杂度都通过框架解决,并且封装后可以带来更多的方便。
通过实践,第二种方式是更好的方式,而rematch框架是其中的佼佼者。
那么rematch是通过哪些方式来提高开发效率的呢?
初始化简化
基本上两行代码就可以初始化store。
import { init } from '@rematch/core'
import * as models from './models'
const store = init({ models })
export default store
聚合Model,自动推导action
状态定义,reducer(同步逻辑修改状态),effects(异步逻辑)在同一个对象中,action的type通过模型名(这是count),reducer和effects的方法名(这里是increment,incrementAsync)中间通过斜杠分割,统一为action的type。
import { createModel } from '@rematch/core'
export const count = createModel({
state: 0, // initial state
reducers: {
// handle state changes with pure functions
increment(state, payload) {
return state + payload
}
},
effects: (dispatch) => ({
// handle state changes with impure functions.
// use async/await for async actions
async incrementAsync(payload, rootState) {
await new Promise(resolve => setTimeout(resolve, 1000))
dispatch.count.increment(payload)
}
})
})
// count/increment, count/incrementAsync 就是action的type了
链式调用,typescript类型推导,IDE自动提示
有了上述的统一model聚合管理,rematch还推出了dispatch的链式调用。
// 普通的disptach调用
dispatch({ type: 'count/' })
// 链式调用
dispatch.count.increment(10)
dispatch.count.incrementAsync(100)
链式调用强大之处是配合typescript和IDE的自动提示功能。当我们键入dispatch. 的时候会自动提示已有的model,比如 这个的count,然后 dispatch.count. 的时候自动提示已有的方法(increment, incrementAsync)。真香~
这个方式使得免去了对于action的类型的记忆,自动提示的重要性毋庸置疑。
在typescript中需要定义Dispatch的类型,才能配合自动提示
const store = init({ models })
// 定义Dispatch的类型,获取rematch store中dispatch类型
export type Dispatch = typeof store.dispatch
// 使用的时候
const dispatch: Dispatch
插件
这部分称不上特别,但是提供了如Loading、immutable的插件,可以方便的解决业务开发中的问题。
感悟
看了rematch的代码,没有什么特别高超的技巧,它要解决的就是开发效率的问题,而这个正是许多使用redux的开发人员的痛点。这让我有几点感悟:
- 选择技术方案的过程中,也需要考虑开发效率的问题,任何事情‘手搓’一定是权宜之计,不能长久,重复的东西能够自动化的,最好是自动化,这样效率的提升比较有效。
- 效率是多方面的,需要考虑一些开发细节,比如自动提示(IDE层面),链式调用(调用模式,人的记忆)等等,这也是一种人性化的体现,不能仅仅考虑技术本身,开发者体验也是挺重要的。
rematch出现后,慢慢的其他的框架也会跟进,往更好的开发体验走,这个挺好的,就好像react hook出现后,大家发现这个方法正好,很多框架也开始拥抱,这是一种理念,实现的方式可以是不同。