虽然我对
redux
的思想非常认同,可在大项目下就是因为这种规范让我非常的难受
redux 的约法三章
- 唯一的数据源且只读
- 定义
action
,用于表述发生了什么?并且携带了怎样的payload
? reducer
根据action.type
不同来做出对应的处理,并返回新的state
为了规范。常见的做法会为不同的action
或constant
创建不同的文件,这也是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()
呢?
他能直接获取到该reducer
在redux
中的定义值
前提你需要正确的设置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
能直接帮你省去创建action
或constant
文件的步骤,提高开发效率。
哦对了,如果你连reducer
和关联reducer
的hooks
都不想创建的话
这我也帮你自动生成好了,期待我的下一篇文章!或直接访问 github.com/erqiu-sj/co…
了解该包更多也可访问 github.com/erqiu-sj/co…