rematch一个redux框架,更是一个效率框架
从这个定义中可以直观的了解到,rematch这个框架是基于redux而建的。
就如rematch的作者所说,其创造的目的就是为了简化在使用redux的过程中所产生开发效率问题。其先驱有知名的dva框架,也是为了解决这个问题,但是rematch更加青出于蓝。

Redux的问题

redux已经提供了一个非常有建设性的理念,redux本身的实现也是简洁的,无可挑剔的,但是它为人诟病的就是需要写许多的重复的样板代码。下图是redux的工作流程:
1_2FuGS7siVavYWxuHtx8ynw.png
所有的具体代码逻辑,都是通过dispatch来调用不同的action,然后触发对应的同步、异步逻辑。redux本身提供的同步逻辑(reducer)的方法,而异步的逻辑通常需要通过使用middleware来实现,比如使用社区的redux-thunk,redux-saga等等库。
这个简单的模型,带来了巨大的开发负担,来来回回需要写许多的样板代码,让开发者苦不堪言,下面来看个简单的例子:

  1. // 0.定义状态
  2. const state = {
  3. hello: 'xx'
  4. }
  5. // 1.定义一个唯一的字符串来标识一个action,action之后是代表了所有触发的同步、异步逻辑
  6. const testConstant = 'action1';
  7. // 2.定义action
  8. const testAction = (payload) => ({ type: testConstant, payload })
  9. // 3.定义reducer
  10. const testReducer = (state, action) => {
  11. switch(action.type) {
  12. case testConstant:
  13. return {...state, ...action.payload}
  14. }
  15. return state;
  16. }
  17. // 4.触发action
  18. dispatch(testAction({ hello: 'world!' }))
  19. 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。

  1. import { init } from '@rematch/core'
  2. import * as models from './models'
  3. const store = init({ models })
  4. export default store

聚合Model,自动推导action

状态定义,reducer(同步逻辑修改状态),effects(异步逻辑)在同一个对象中,action的type通过模型名(这是count),reducer和effects的方法名(这里是increment,incrementAsync)中间通过斜杠分割,统一为action的type。

  1. import { createModel } from '@rematch/core'
  2. export const count = createModel({
  3. state: 0, // initial state
  4. reducers: {
  5. // handle state changes with pure functions
  6. increment(state, payload) {
  7. return state + payload
  8. }
  9. },
  10. effects: (dispatch) => ({
  11. // handle state changes with impure functions.
  12. // use async/await for async actions
  13. async incrementAsync(payload, rootState) {
  14. await new Promise(resolve => setTimeout(resolve, 1000))
  15. dispatch.count.increment(payload)
  16. }
  17. })
  18. })
  19. // count/increment, count/incrementAsync 就是action的type了

链式调用,typescript类型推导,IDE自动提示

有了上述的统一model聚合管理,rematch还推出了dispatch的链式调用。

  1. // 普通的disptach调用
  2. dispatch({ type: 'count/' })
  3. // 链式调用
  4. dispatch.count.increment(10)
  5. dispatch.count.incrementAsync(100)

链式调用强大之处是配合typescript和IDE的自动提示功能。当我们键入dispatch. 的时候会自动提示已有的model,比如 这个的count,然后 dispatch.count. 的时候自动提示已有的方法(increment, incrementAsync)。真香~
这个方式使得免去了对于action的类型的记忆,自动提示的重要性毋庸置疑。
在typescript中需要定义Dispatch的类型,才能配合自动提示

  1. const store = init({ models })
  2. // 定义Dispatch的类型,获取rematch store中dispatch类型
  3. export type Dispatch = typeof store.dispatch
  4. // 使用的时候
  5. const dispatch: Dispatch

插件

这部分称不上特别,但是提供了如Loading、immutable的插件,可以方便的解决业务开发中的问题。

感悟

看了rematch的代码,没有什么特别高超的技巧,它要解决的就是开发效率的问题,而这个正是许多使用redux的开发人员的痛点。这让我有几点感悟:

  1. 选择技术方案的过程中,也需要考虑开发效率的问题,任何事情‘手搓’一定是权宜之计,不能长久,重复的东西能够自动化的,最好是自动化,这样效率的提升比较有效。
  2. 效率是多方面的,需要考虑一些开发细节,比如自动提示(IDE层面),链式调用(调用模式,人的记忆)等等,这也是一种人性化的体现,不能仅仅考虑技术本身,开发者体验也是挺重要的。

rematch出现后,慢慢的其他的框架也会跟进,往更好的开发体验走,这个挺好的,就好像react hook出现后,大家发现这个方法正好,很多框架也开始拥抱,这是一种理念,实现的方式可以是不同。