React-Redux进阶(像VUEX一样运用Redux)

媒介

Redux是一个异常有用的状况治理库,关于大多数运用React库的开发者来讲,Redux都是会接触到的。在运用Redux享用其带来的轻易的同时, 我们也深受其题目的搅扰。

redux的题目

之前在别的一篇文章Redux基本中,就有提到以下这些题目

  • 纯洁。Redux只支撑同步,让状况可展望,轻易测试。 但不处置惩罚异步、副作用的状况,而把这个丢给了其他中间件,诸如redux-thunkredux-promiseredux-saga等等,挑选多也轻易形成杂沓~
  • 烦琐。那末写过Redux的人,都晓得actionreducer以及你的营业代码异常烦琐,模板代码异常多。然则~,这也是为了让数据的活动清楚清楚明了。
  • 机能。粗犷地、级联式革新视图(运用react-redux优化)。
  • 分型。原生 Redux-react 没有分形构造,中间化 store

内里除了机能这一块能够运用react-redux举行优化,其他的都是开发者不能不面临的题目,关于代码有洁癖的人,烦琐这一点确实是无法忍受的。

计划目的

假如你运用过VUEX的话, 那末关于它的API肯定会相对喜好许多,固然,vuex不是immutable,所以关于时刻游览这类营业不太友爱。不过,我们能够自身完成一个具有vuex的简约语法和immutable属性的redux-x(瞎定名)。

先看一下我们想要的目的是什么样的?
起首, 我们再./models内里定义每个子state树,内里带有namespace、state、reducers、effects等属性, 以下:

export default {
  // 定名空间
  namespace: 'common',
  // 初始化state
  state: {
    loading: false,
  },
  // reducers 同步更新 类似于vuex的mutations
  reducers: {
    updateLoadingStatus(state, action) {
      return {
        ...state,
        loading: action.payload
      }
    },
  },
  // reducers 异步更新 类似于vuex的actions
  efffects: {
    someEffect(action, store) {
      // some effect code
      ...
      ... 
      // 将效果返回
      return result
    }
  }
}

经由过程上面的完成,我们基本处理了Redux自身的一些瑕疵

1.在effects中寄存的要领用于处理不支撑异步、副作用的题目  

2.经由过程兼并reducer和action, 将模板代码大大削减  

3.具有分型构造(namespace),而且中间化处置惩罚

怎样完成

暴露的接口redux-x

起首,我们只是在外层封装了一层API轻易运用,那末说到底,传给redux的combineReducers照样一个redux对象。别的一个则是要处置惩罚副作用的话,那就必需运用到了中间件,所以末了我们暴露出来的函数的返回值应当具有上面两个属性,以下:

import reduxSimp from '../utils/redux-simp' // 内部完成
import common from './common' // models文件下common的状况治理
import user from './user' // models文件下user的状况治理
import rank from './rank' // models文件下rank的状况治理

const reduxX = reduxSimp({
  common,
  user,
  rank
})
export default reduxX
const store = createStore(
  combineReducers(reduxX.reducers),  // reducers树
  {},
  applyMiddleware(reduxX.effectMiddler)  //  处置惩罚副作用中间件
)

第一步, 我们先完成一个暴露出来的函数reduxSimp,经由过程他对model内里各个属性举行加工,也许的代码以下:

const reductionReducer = function() { // somecode }
const reductionEffects = function() { // somecode }
const effectMiddler = function() { // somecode }
/**
 * @param {Object} models
 */
const simplifyRedux = (models) => {
  // 初始化一个reducers 末了传给combinReducer的值 也是终究复原的redux
  const reducers = {}
  // 遍历传入的model
  const modelArr = Object.keys(models)
  modelArr.forEach((key) => {
    const model = models[key]
    // 复原effect
    reductionEffects(model)
    // 复原reducer,同时经由过程namespace属性处置惩罚定名空间
    const reducer = reductionReducer(model)
    reducers[model.namespace] = reducer
  })
  // 返回一个reducers和一个特地处置惩罚副作用的中间件
  return {
    reducers,
    effectMiddler
  }
}

复原effects

关于effects, 运用的时刻以下(没什么区分):

props.dispatch({
  type: 'rank/fundRankingList_fetch',
  payload: {
    fundType: props.fundType,
    returnType: props.returnType,
    pageNo: fund.pageNo,
    pageSize: 20
  }
})

复原effects的思绪也许就是先将每个model下的effect网络起来,同时加上定名空间作为前缀,将副作用的key即type 和相对应的要领value离开寄存在两个数组内里,然后定义一个中间件,每当有一个dispatch的时刻,搜检key数组中是不是有相符的key,假如有,则挪用对应的value数组内里的要领。

// 常量 离别寄存副作用的key即type 和相对应的要领
const effectsKey = []
const effectsMethodArr = []  
/**
 * 复原effects的函数
 * @param {Object} model
 */
const reductionEffects = (model) => {
  const {
    namespace,
    effects
  } = model
  const effectsArr = Object.keys(effects || {})

  effectsArr.forEach((effect) => {
    // 寄存对应effect的type和要领
    effectsKey.push(namespace + '/' + effect)
    effectsMethodArr.push(model.effects[effect])
  })
}

/**
 * 处置惩罚effect的中间件 详细参考redux中间件
 * @param {Object} store
 */
const effectMiddler = store => next => (action) => {
  next(action)
  // 假如存在对应的effect, 挪用其要领
  const index = effectsKey.indexOf(action.type)
  if (index > -1) {
    return effectsMethodArr[index](action, store)
  }
  return action
}

复原reducers

reducers的运用也是和本来没有区分:

props.dispatch({ type: 'common/updateLoadingStatus', payload: true })

代码完成的思绪就是末了返回一个函数,也就是我们一般写的redux函数,函数内部遍历对应定名空间的reducer,找到婚配的reducer实行后返回效果

/**
 * 复原reducer的函数
 * @param {Object} model 传入的model对象
 */
const reductionReducer = (model) => {
  const {
    namespace,
    reducers
  } = model

  const initState = model.state
  const reducerArr = Object.keys(reducers || {})

  // 该函数即redux函数
  return (state = initState, action) => {
    let result = state
    reducerArr.forEach((reducer) => {
      // 返回婚配的action
      if (action.type === `${namespace}/${reducer}`) {
        result = model.reducers[reducer](state, action)
      }
    })
    return result
  }
}

终究代码

终究的代码以下,加上了一些错误判断:

// 常量 离别寄存副作用的key即type 和相对应的要领
const effectsKey = []
const effectsMethodArr = []

/**
 * 复原reducer的函数
 * @param {Object} model 传入的model对象
 */
const reductionReducer = (model) => {
  if (typeof model !== 'object') {
    throw Error('Model must be object!')
  }

  const {
    namespace,
    reducers
  } = model

  if (!namespace || typeof namespace !== 'string') {
    throw Error(`The namespace must be a defined and non-empty string! It is ${namespace}`)
  }

  const initState = model.state
  const reducerArr = Object.keys(reducers || {})

  reducerArr.forEach((reducer) => {
    if (typeof model.reducers[reducer] !== 'function') {
      throw Error(`The reducer must be a function! In ${namespace}`)
    }
  })

  // 该函数即redux函数
  return (state = initState, action) => {
    let result = state
    reducerArr.forEach((reducer) => {
      // 返回婚配的action
      if (action.type === `${namespace}/${reducer}`) {
        result = model.reducers[reducer](state, action)
      }
    })
    return result
  }
}

/**
 * 复原effects的函数
 * @param {Object} model
 */
const reductionEffects = (model) => {
  const {
    namespace,
    effects
  } = model
  const effectsArr = Object.keys(effects || {})

  effectsArr.forEach((effect) => {
    if (typeof model.effects[effect] !== 'function') {
      throw Error(`The effect must be a function! In ${namespace}`)
    }
  })
  effectsArr.forEach((effect) => {
    // 寄存对应effect的type和要领
    effectsKey.push(namespace + '/' + effect)
    effectsMethodArr.push(model.effects[effect])
  })
}

/**
 * 处置惩罚effect的中间件 详细参考redux中间件
 * @param {Object} store
 */
const effectMiddler = store => next => (action) => {
  next(action)
  // 假如存在对应的effect, 挪用其要领
  const index = effectsKey.indexOf(action.type)
  if (index > -1) {
    return effectsMethodArr[index](action, store)
  }
  return action
}

/**
 * @param {Object} models
 */
const simplifyRedux = (models) => {
  if (typeof models !== 'object') {
    throw Error('Models must be object!')
  }
  // 初始化一个reducers 末了传给combinReducer的值 也是终究复原的redux
  const reducers = {}
  // 遍历传入的model
  const modelArr = Object.keys(models)
  modelArr.forEach((key) => {
    const model = models[key]
    // 复原effect
    reductionEffects(model)
    // 复原reducer,同时经由过程namespace属性处置惩罚定名空间
    const reducer = reductionReducer(model)
    reducers[model.namespace] = reducer
  })
  // 返回一个reducers和一个特地处置惩罚副作用的中间件
  return {
    reducers,
    effectMiddler
  }
}

export default simplifyRedux

思索

怎样连系Immutable.js运用?

    原文作者:菜的黑人牙膏
    原文地址: https://segmentfault.com/a/1190000018127962
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞