存储影响全球状态的减速器的位置

时间:2017-02-15 19:32:31

标签: javascript reactjs ecmascript-6 redux

这是我的店铺形状:

export default {
    isRequesting: false,
    requestError: null,
    things: [],
    otherThings: []
}

从服务器提取thingsotherThings时,isRequesting会发生变化,requestError可能会被更改。目前,我在reducers/thingReducer.jsreducers/otherThingReducer.js之类的缩减器中更改了这些内容,例如:

// reducers/thingReducer.js
import { combineReducers } from 'redux'
import { LOAD_THINGS_REQUESTING, LOAD_THINGS_SUCCESS, LOAD_THINGS_ERROR } from '../actions/actionTypes'
import initialState from './initialState'


export function things(state = initialState.things, action) {
    switch(action.type) {
        case LOAD_THINGS_SUCCESS: 
            return action.things
        default:
            return state
    }
}

export function isRequesting(state = initialState.isRequesting, action) {
    switch(action.type) {
        case LOAD_THINGS_REQUESTING:
            return true
        case LOAD_THINGS_SUCCESS:
            return false
        case LOAD_THINGS_ERROR:
            return false
        default:
            return state
    }
}

export function requestError(state = initialState.requestError, action) {
    switch(action.type) {
        case LOAD_THINGS_ERROR:
            return action.error
        default:
            return state
    }
}

const thingsReducer =  {
    things,
    isRequesting,
    requestError
}

export default thingsReducer

正如您所看到的,我在isRequesting中有requestErrorthingReducer的缩减器,我在otherThingReducer也有同样的东西。

您可能还会看到我导出每个功能,以便我可以在rootReducer.js

中执行以下操作
const rootReducer = combineReducers({
    ...thingReducer,
    ...otherThingReducer
})

export default rootReducer

我从未在示例代码(传播reducers)中看到过这种情况,这让我认为每个reducer文件只应包含一个函数。我知道这是两个问题:

  1. isRequestingrequestError是否应该存在于各个reducer文件中(即使它们是全局状态的一部分)

  2. 如果是这样的话,它们应该如上所述进行传播和组合。即使1)的答案为否,当每个reducer文件实际需要多个reducer时,我可以使用这种spread / combine方法吗?

2 个答案:

答案 0 :(得分:2)

你没有扩散减速器。 thingsReducer是一个包含reducers的对象,而你正在传播该对象。如果您使用thingsReducer,可以使combineReducers成为嵌套的reducer,但我认为没有必要:

const thingsReducer = combineReducers({
    things,
    isRequesting,
    requestError
})

至于您的问题,isRequestingrequestError的位置并不重要。通常的做法是将每个reducer放在自己的模块中(例如,查看Ducks https://github.com/erikras/ducks-modular-redux),但这取决于你。您也可以完全删除thingsReducer并将缩减器直接导入rootReducer.js,如下所示:

import {things, isRequesting, requestError} from './reducers/thingReducer'
// Or if you decided to put each reducer in its own file
// import things from './reducers/thingsReducer' 
// import isRequesting from './reducers/isRequestingReducer' 
// ...

const rootReducer = combineReducers({
    things,
    isRequesting,
    requestError,
    // do the same for otherThingReducer reducers
})

export default rootReducer

更新: 要在评论中回答您的问题,您可以执行以下操作来简化代码。由于您正在重复使用许多操作,因此可以将reducers合并为如下所示:

export function things(state = initialState, action) {
    switch(action.type) {
        case LOAD_THINGS_SUCCESS: 
            return {
                ...state,
                things: action.things,
                isRequesting: false
            }
        case LOAD_THINGS_ERROR: 
            return {
                ...state,
                requestError: action.error,
                isRequesting: false
            }
        case LOAD_THINGS_REQUESTING: 
            return {
                ...state,
                isRequesting: true
            }

        default:
            return state
    }
}

如果您这样做,则只需将默认things缩减器导入rootReducer

答案 1 :(得分:1)

在缩减器文件的底部,例如things缩减器,您可以像这样导出一个常量:

export const thing = combineReducers({ things, isRequesting, requestError });

然后在你的root reducer中,你以相同的方式组合它们:

const rootReducer = combineReducers({
    thingReducer,
    otherThingReducer
})

export default rootReducer

这是一个意见问题,但我更喜欢创建一个适合您的thingsisRequestingrequestError的缩减器,如下所示:

// reducers/thingReducer.js
import { combineReducers } from 'redux'
import { LOAD_THINGS_REQUESTING, LOAD_THINGS_SUCCESS, LOAD_THINGS_ERROR } from '../actions/actionTypes'
import initialState from './initialState'

const initialThing = {
  data: {},
  isLoading: false,
  isError: false
}

const things = (
  state = initialThing,
  action
) => {
    switch(action.type) {
      case LOAD_THING_REQUESTING:
        return {
          ...state,
          isLoading: true
        };
      case LOAD_THINGS_SUCCESS: 
        return {
          ...state,
          data: action.things,
          isLoading: false,
          isError: false
        };
      case LOAD_THINGS_ERROR:
        return {
          ...state,
          isLoading: false,
          isError: true
        };
      default:
        return state;
    }
}

export default thingsReducer = combineReducers({ things, someOtherReducerFunction });