rc-redux-model 介绍
PDKSophia opened this issue · 0 comments
Why rc-redux-model ?
相信大家都了解 redux
,并且也认同这种数据流的方式(毕竟不认同,你也不会用嘛~),然,世间万物,皆有利弊。
以我为例,每次起一个项目,我都需要 :
- 脚手架
create-react-app
快速生成一个应用框架,进行开发 - 安装
redux
进行数据状态管理 - 安装
react-redux
,调用 Provider 提供者模式,使得子组件都能取到 store 值 - 如果想要解决异步请求,我也许还需要安装一个
redux-saga
/redux-thunk
- 如果想看到日志,那么我还会安装
redux-logger
- ...
看似一顿操作猛如虎,其实心中已经 MMP,我会想,这么多前置工作,是不是让我的开发成本更高了呢?
为了解决异步 Action,我需要按照 redux-saga 或者 redux-thunk,从而处理异步问题,以 redux-saga 为例 :
在使用中,我发现 redux
+ redux-saga
让我的 [重复性] 工作变多(逐步晋升 CV 工程师),因为它存在啰嗦的样板代码。
举个 🌰 : 异步请求,获取用户信息,我需要创建 sagas/user.js
、reducers/user.js
、actions/user.js
,为了统一管理 const,我还会有一个 const/user.js
,然后在这些文件之间来回切换。
分文件应该是一种默认的规范吧?反正我实习的时候,是分文件的;现在组里,是分文件的;看一些优秀库(star 多),也是分文件的;包括看 dva 的介绍,它也提到了问题
// const/user.js
const FETCH_USER_INFO = 'FETCH_USER_INFO'
const FETCH_USER_INFO_SUCCESS = 'FETCH_USER_INFO_SUCCESS'
// actions/user.js
export function fetchUserInfo(params, callback) {
return {
type: FETCH_USER_INFO,
params,
callback,
}
}
// sagas/user.js
function* fetchUserInfoSaga({ params, callback }) {
const res = yield call(fetch.callAPI, {
actionName: FETCH_USER_INFO,
params,
})
if (res.code === 0) {
yield put({
type: FETCH_USER_INFO_SUCCESS,
data: res.data,
})
callback && callback()
} else {
throw res.msg
}
}
// reducers/user.js
function userReducer(state, action) {
switch (action.type) {
case FETCH_USER_INFO_SUCCESS:
return Immutable.set(state, 'userInfo', action.data)
}
}
没错, 这种样板代码,简直就是 CV 操作,只需要 copy 一份,修改一下名称,对我个人而言,这会让我不够专注,分散管理 const、action、saga、reducer 一套流程,需要不断的跳跃思路。
而且文件数量会变多,我是真的不喜欢如此繁琐
的流程,有没有好的框架能帮我把这些事都做完呢?
dva
世间万物存在,必然有它自身的价值和意义。dva 的出现,肯定是解决了一些问题。我们看看 dva 官网怎么说的 ~~
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
有意思,但是因为 dva 身负重任,对我而言,使用它太过于“笨重”,我只是想取其精华,去其内置,我就只想用它写状态管理的方式: 在 model 里边,写完 reducer, state, action
再一次与 JPL 同学交流的过程中,发现他也有这种想法,同时他已经写了一个简单的中间件,在他们组里用了起来,出于学习以及如何写一个中间件,在参考它的代码之后,我也开始尝试写一个 redux 的中间件,并且内部支持默认的 action,让开发更加简洁,释放键盘上的 C 与 V ,同时对于 Immutable 的支持以及错误类型的检测,让你的 state
更加“合法”
于是 rc-redux-model 就这样出现了...
What's rc-redux-model ?
rc-redux-model 是一个中间件,提供一种更为简洁和方便的数据状态管理[书写方式]。参考了 dva 的数据流方案,在一个 model 文件中写所有的 action
、reducer
、state
,解读了 redux-thunk
的源码,内部实现了一个中间价,同时提供默认行为 action,调用此 action 可以直接修改任意值的 state,例如 :
只需要定义一个 model
export default {
namespace: 'reduxModel',
state: {
testA: '',
testB: [],
},
}
那么 rc-redux-model
会自动帮你注册 action 及 reducers,等价于 action 和 reducers 不用你自己写了,如下 :
export default {
namespace: 'reduxModel',
state: {
testA: '',
testB: [],
},
action: {
settestA: ({ commit, currentAction }) => {
commit({
type: 'SET_REDUXMODEL_TESTA',
payload: currentAction.payload,
})
},
settestB: ({ commit, currentAction }) => {
commit({
type: 'SET_REDUXMODEL_TESTB',
payload: currentAction.payload,
})
},
// 推荐使用此action进行修改reducers值
setStore: ({ dispatch, currentAction }) => {
dispatch({
type: `reduxModel/change${currentAction.payload.key}`,
payload: currentAction.payload.values,
})
},
},
reducers: {
['SET_REDUXMODEL_TESTA'](state, payload) {
return {
...state,
...payload,
}
},
['SET_REDUXMODEL_TESTB'](state, payload) {
return {
...state,
...payload,
}
},
},
}
那么你只需要在组件中,调用的默认 Action 即可
class MyComponent extends React.Component {
componentDidMount() {
this.props.dispatch({
type: 'reduxModel/setStore',
payload: {
key: 'testA',
values: '666',
},
})
}
}
hooks ?
hooks 的出现,让我们看到了处理复杂且重复逻辑的曙光,那么问题来了,在 hooks 中能不能用 rc-redux-model
,我想说 : “想啥呢,一个是 react 的特性,一个是 redux 的中间件, 冲突吗?”
// Usage with React Redux: Typing the useSelector hook & Typing the useDispatch hook
// https://redux.js.org/recipes/usage-with-typescript#usage-with-react-redux
import { useDispatch } from 'react-redux'
export function useFetchUserInfo() {
const dispatch = useDispatch()
return async (userId: string) => {
// 这里我选择自己处理异步,异步请求完后,再把数据传到 reducer 中
const res = await callAPI(userId)
if (res.code === 200) {
dispatch({
type: 'userModel/setStore',
payload: {
key: 'userInfo',
values: res.data,
},
})
}
}
}
强调说明
rc-redux-model 出发点在于解决我繁琐重复的工作,store 文件分散,state 类型和赋值错误的问题,为此,对于跟我一样的用户,提供了一个写状态管理较为[舒服]的书写方式,大部分情况下兼容原先项目~
- 为了解决[store 文件分散],参考借鉴了 dva 写状态管理的方式,一个 model 中写所有的
action、state、reducers
- 为了解决[繁琐重复的工作],提供默认的 action,用户不需要自己写修改 state 的 action,只需要调用默认提供的
[model.namespace/setStore]
即可,从而将一些重复的代码从 model 文件中剔除 - 为了解决[state 类型和赋值错误],在每次修改 state 值时候,都会进行检测,如果不通过则报错提示
How to use
FAQ
可在现有的项目中兼容使用,具体使用方式,可参考完整例子