2017-02-15 5 views
2

Это мой магазин форма:Где хранить редукторы влияет глобальное состояние

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

Когда things и otherThings они загружаются с сервера, isRequesting изменяется и requestError потенциально могут быть изменены. В настоящее время, я меняю их в редукторах, как reducers/thingReducer.js и reducers/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 и requestError в моем thingReducer и у меня то же самое в otherThingReducer, а также.

Вы также можете видеть, что я экспортировать каждую функцию, так что я могу сделать следующее в rootReducer.js

const rootReducer = combineReducers({ 
    ...thingReducer, 
    ...otherThingReducer 
}) 

export default rootReducer 

Я никогда не видел это сделано в примере кода (разводя восстановителей), которая заставляет меня думать, каждый файл редуктора должен содержать только одну функцию. Я понимаю, что это два вопроса:

  1. Должен isRequesting и requestError живут в отдельных файлах редуктора (даже если они являются частью глобального состояния)

  2. Если да, то они должны быть распространены и в сочетании, как Я сделал это выше. Даже если ответ на 1) нет, могу ли я использовать этот метод распространения/объединения, когда каждый файл редуктора фактически требует нескольких редукторов?

ответ

2

Вы не распространяете редукторы. thingsReducer - это объект, который содержит редукторы, и вы распространяете этот объект. Вы можете сделать thingsReducer вложенный редуктор, если вы используете combineReducers, но я не вижу необходимости в том, что:

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

Что касается ваших вопросов, то на самом деле не имеет значения, где isRequesting и requestError расположены. Обычная практика заключается в том, чтобы каждый редуктор был в своем собственном модуле (проверьте 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 

UPDATE: Для того, чтобы ответить на ваш вопрос в комментариях, вы можете сделать следующее, чтобы упростить код. Так как вы повторно много действий, вы можете объединить ваши восстановителей в один, как это:

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.

+0

Спасибо, я положу их в разные файлы, чтобы оставаться СУХОЙ. И тогда, я думаю, больше не нужно распространять - спасибо! –

+0

На самом деле, так как у меня есть 'LOAD_THINGS_SUCCESS' и т. Д., Не имеет ли смысл связывать их с редуктором' thing'? Существует ли обычная практика установки независимого 'LOAD_SUCCESS' для любых вызовов AJAX? Если да, не было бы беспорядочно отправлять «LOAD_SUCCESS» и «LOAD_PARTS_SUCCESS»? –

+0

Вы можете определенно повторно использовать действия из других модулей или иметь общий общий набор редукторов. Другая практика (снова у Ducks) - это префикс имени действия с именем модуля/редуктора. например 'thing/LOAD_THINGS_REQUESTING' и' otherThing/LOAD_THINGS_REQUESTING'. Я предпочитаю не многократно использовать действия и использовать префиксный подход, чтобы помочь мне в отладке и отслеживании потока моего приложения. –

1

В нижней части ваших редукторных файлов, таких как ваш things редуктор, вы можете экспортировать константу следующим образом:

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

, а затем в корневом редукторе, вы объедините их таким же образом:

const rootReducer = combineReducers({ 
    thingReducer, 
    otherThingReducer 
}) 

export default rootReducer 

Это вопрос мнения, но я предпочитаю, чтобы создать редуктор, который соответствует вашим things, isRequesting и requestError в одну функцию следующим образом:

// 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 }); 
+0

Интересно, спасибо за ваше предложение , Я сначала попытался сделать вещь «... state», но подумал, что это будет считаться анти-шаблоном - не вижу причин, почему это плохо. Ваши приложения были относительно сложными? –

+1

Это не анти-шаблон и, пожалуй, самый сжатый способ возврата нового объекта из редуктора (помните, мы не хотим мутировать состояние, всегда возвращаем новый объект!). Вы также можете выполнить это, используя функцию утилиты назначения из lodash, такую ​​как '_.assign ({}, state, {data: newDataHere})' или простой старый объект Object.assign, то есть 'Object.assign ({}, state, {data: newDataHere}) ' –

+1

Вот хороший ресурс для оператора спредов в редуксе, непосредственно из документов redux: D http://redux.js.org/docs/recipes/UsingObjectSpreadOperator.html –

Смежные вопросы