redux(3)-分模块+异步操作

分模块:combineReducers

基本使用

1、store注册过程中文件拆分

        每一个模块就会包含四个基础文件,在其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

具体文件图如下:

redux(3)-分模块+异步操作_第1张图片

2、使用

 现在访问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;
    }, {});
  };
}

异步操作:redux-thunk

基本使用

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: '小米' })))

end

下一篇介绍rtk

你可能感兴趣的:(react,前端,javascript,开发语言)