每一个模块就会包含四个基础文件,在其index.js中导出这个模块的reducer和actionCreators,user/index.js的内容如下:
// 需要默认导出reducer,并分别导出actionCreators
import reducer from './reducer.js'
export default reducer
export * from './actionCreators'
我们还需要在redux下建一个index.js接收这些模块的reducer,并且在这里使用combineReducers(从redux从导入)合并reducer,最后创建store,redux/index.js代码如下 :
// 使用combineReducer进行reducer合并
import { combineReducers, createStore } from 'redux'
import userReducer from './user'
const reducer = combineReducers({
user: userReducer
})
const Store = createStore(reducer)
export default Store
具体文件图如下:
现在访问state下面的值,需要在state后加上模块名。
const age = useSelector((state) => state.user.age)
我们能实现一个简单的combineReducers,主要操作就是需要执行每个模块的reducer函数,拿到其返回state后依据模块名合并为一个新的state。具体代码如下:
function myCombineReducers(reducers) {
// reducer是个函数,所以这里返回函数。
// 到时候redux会把上一次的state和action传过来,所以这个函数需要接收state和action
return function(state = {}, action) {
// reducer函数内部需要返回新的state,所以这里也会返回一个新对象
return Object.keys(reducers).reduce((nextState, key) => {
// 遍历传进来的reducers对象,执行每个模块对应的reducer,就能拿到模块的state。
// 最后合并到一个对象,作为新的state
nextState[key] = reducers[key](state[key], action);
return nextState;
}, {});
};
}
1、定义函数类型的action
在redux/user/actionCreators.js中,首先会定义一个对象类型的action用于设置state,然后定义个函数类型的action。
在这个函数action中,先请求异步数据,得到数据后dispatch对象类型的action去修改state。
export const setData_action = (data) => ({
type: actionTypes.SET_DATA,
data
})
// 异步请求时,需要返回一个函数,而不是action对象,这个函数接收dispatch和getState方法。
export const getData_action = (id) => async (dispatch, getState) => {
// 在返回的函数中进行请求,拿到数据后进行dispatch设置state的action,最终完成设置state的操作
let res = await fetch(`http://localhost:3002/data.txt?id=${id}`)
res = await res.json()
dispatch(setData_action(res))
}
2、引入redux-thunk
redux默认不支持函数类型action,需要使用redux-thunk这个中间件使其支持。
在createStore时使用thunk,即修改redux/index.js文件。代码如下:
import { applyMiddleware, combineReducers, createStore } from 'redux'
import thunk from 'redux-thunk'
//....其他代码
// 利用中间件thunk,使action可以为函数
const Store = createStore(reducer, applyMiddleware(thunk))
在使用thunk时,我们能往额外注入一些参数,在函数action中能拿到。具体步骤如下:
1、在使用thunk时,使用thunk.withExtraArgument传入额外的参数
const Store = createStore(reducer, applyMiddleware(thunk.withExtraArgument({ name: '小米' })))
2、在函数action中,从第三个参数开始就是额外传进来的参数了。
export const getData_action = (id) => async (dispatch, getState, arg) => {
console.log(arg, '额外传递的参数')
let res = await fetch(`http://localhost:3002/data.txt?id=${id}`)
res = await res.json()
dispatch(setData_action(res))
}
【这在多个thunk函数中共享某些值(例如,API接口或数据库连接)时非常有用。】
简单实现下redux-thunk,他的主要处理逻辑是:
处理逻辑:若action是函数,则将dispatch,getState等传给他并执行;若是对象将action传给下一个中间件。
具体代码如下:
function createThunkMiddleware(...arg) {
// thunk含自身包含三层回调,
// 第一层能拿到dispatch和getState等和Store有关的api,
// 第二层能拿到next函数,next用于执行下一个中间件,并把action给下一个中间件。
// 第三层接收action,也是真正处理逻辑的地方。
// 处理逻辑:若action是函数,则将dispatch,getState等传给他并执行;若是对象将action传给下一个中间件。
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState,...arg);
}
return next(action);
};
}
const thunk = createThunkMiddleware()
// 实现withExtraArgument
thunk.withExtraArgument = createThunkMiddleware
const Store = createStore(reducer, applyMiddleware(thunk.withExtraArgument({ name: '小米' })))
下一篇介绍rtk