改善redux现状

529 阅读4分钟

虽然我对redux 的思想非常认同,可在大项目下就是因为这种规范让我非常的难受

redux 的约法三章

  • 唯一的数据源且只读
  • 定义action,用于表述发生了什么?并且携带了怎样的payload
  • reducer 根据action.type不同来做出对应的处理,并返回新的state

为了规范。常见的做法会为不同的actionconstant创建不同的文件,这也是redux官方推荐的规范

对于这种规范多次执行后,我发现我更多的时间会被浪费在定义上,这让我心力憔悴

并且我理解在reducer中充斥这大量的swtich if else 不够语意化且逻辑复杂后难以维护**(个人观点)**

是时候改变了

为了改变现状,我认为一个reducer在被定义时就应该兼顾定义action 和定义actionHandler 的能力和一些额外的能力**(可滑至最后一段)**

为了更好的语义化

import { CreateReducer , getAllValsWithActionCollectionHelper , createStore , combineReducers  } from '@zealforchange/conciseredux'
type State = { age: number }
type actionPyload = { age: number }
type action = getAllValsWithActionCollectionHelper<{
    SET_AGE : 'setAge'
}>
const state = { age: 19 }
// 泛型为选填参数,会有更好的类型提示
const reducer =  new CreateReducer<State, actionPyload, action>(state).addAction('setAge', (state,actionPayload) => {
    return { ...state , age: actionPayload.age }
}).setReducerKey('reducer') // setReducerKey函数在后会讲解

const store = createStore(
  combineReducers({
    reducer: reducer.finish(), // finish() 用于返回一个reducer函数
  })
)
// redux 内部会生成一个 { reducer : { age: 19 } } 对象

这是实在是太酷了!

可是这还远远不够,因为还有很多额外的能力未能实现

试想一个场景

当你使用react-redux 提供的更新函数去更新现有reducer的值时

// 伪代码
// 此的dispatch函数是由react-redux提供的方法封装而成
// 我想将 age 修改为 20 ,这很简单没错,这一切非常的自然
dispatch({age: 20})
// 可是如果我想通过更新后的值去调用一个接口查询age === 20 的用户有哪些时,这就是一个大问题了
const curReducer = useSelector( state => state.reducer )
console.log(curReducer.age) // 19
axios({ params : { age: curReducer.age } }) // 19

我明明更新了为什么查询时的参数age会是19呢?

在函数式组件中更新,你只能捕捉当前渲染时的值,这是react有意而为的

好吧,该如何解决刚才的问题呢?

我的建议是将所有的reducer封装成一个hooks

import { useDispatch , useSelector } from 'react-redux';
import { bindActionCreators } from '@zealforchange/conciseredux'
import { reducer } from './reducer/reducer'

function useReducer() {
    //  注意点1 reducer.getCallBackAll()
    const dispatcherWithReducer =  bindActionCreators(reducer.getCallBackAll(),useDispatch())
    const curStateWithReducer = useSelector( state => state.reducer )
    // 注意点2 reducer.getCurState()
    const curStateWithReducerForRedux = reducer.getCurState()
    return { dispatcherWithReducer , curStateWithReducer , curStateWithReducerForRedux }
}

导出一个对象是因为使用时有更好的类型提示,而数组解构只能硬记返回值顺序

问题迎刃而解

// 伪代码
// 此的dispatch函数是由react-redux提供的方法封装而成
// 我想将 age 修改为 20 ,这很简单没错,这一切非常的自然
dispatch({age: 20})
// 可是如果我想通过更新后的值去调用一个接口查询age === 20 的用户有哪些时,这就是一个大问题了
const curReducer = useSelector( state => state.reducer )
console.log(curReducer.age) // 19 此时的取值并不是取的redux内部的age
axios({ params : { age: curReducer.age } }) // 19 此时的值是由react维护,实际redux内的age已更新

// 改造后

const { dispatcherWithReducer , curStateWithReducerForRedux } = useReducer()

dispatcherWithReducer.setAge('setAge',{age : 20})

console.log(curStateWithReducerForRedux.age) // 20  从redux中取值

axios({ params : { age: curStateWithReducerForRedux.age } }) // 20

有两个注意点

reducer.getCallBackAll()
reducer.getCurState()

reducer是从开头实例代码new CreateRedcuer() 创建而来

reducer.getCallBackAll() 他会返回给你一个定义好了的actionHandler

可为什么是 dispatcherWithReducer.setAge('setAge',{age : 20})

这个 .setAge 从何定义而来?

该函数从addAction时就被生成,这不就是我想要的在创建action时候同时创建actionHandler吗?

这实在是太棒了我的老伙计!

reducer.getCurState() 呢?

他能直接获取到该reducerredux中的定义值

前提你需要正确的设置setReducerKey ,并指向redux中的某个reducer的key

const reducer =  new CreateReducer<State, actionPyload, action>(state).addAction('setAge', (state,actionPayload) => {
    return { ...state , age: actionPayload.age }
}).setReducerKey('reducer') // setReducerKey('reducer')  中的reducer 应该是redux中存在的key

const store = createStore(
  combineReducers({
    reducer: reducer.finish(), 
  })
)

// redux 内部会生成一个 { reducer : { age: 19 } } 对象

总结

通过CreateReducer 创建的reducer 能直接帮你省去创建actionconstant文件的步骤,提高开发效率。

哦对了,如果你连reducer和关联reducerhooks都不想创建的话

这我也帮你自动生成好了,期待我的下一篇文章!或直接访问 github.com/erqiu-sj/co…

了解该包更多也可访问 github.com/erqiu-sj/co…