Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the initial state at root level in combineReducers?

I need to update multiple properties on my application state with single reducer. Later I'm using combineReducers redux helper that combines all the reducers. Problem is, all the other reducers operate one level down from the root of the state (that is, on a property), except this one that I need to pass the whole state to.

How do I use the combineReducers function to pass the root state?

const App = combineReducers({
  pages: combineReducers({
    browse: combineReducers({
      numOfItems: loadMoreItems,
      filter: setFilter
    })
  }),
  <rootState>: openPage,
  favoriteItems: addItemToFavorites,
  inBasketItems: addItemToBasket
})

What do I place in <rootState> ?

like image 225
Aurimas Avatar asked Jan 21 '17 15:01

Aurimas


People also ask

How do you use initial state in reducer?

There are two main ways to initialize state for your application. The createStore method can accept an optional preloadedState value as its second argument. Reducers can also specify an initial value by looking for an incoming state argument that is undefined , and returning the value they'd like to use as a default.

How do I set Redux state to initial state?

You can set it at the reducers . Reducers can also set initialState by looking at the incoming state argument (which would be undefined if createStore is not called with initialState ) and returning the values they would like to use as default.

How does Combinereducer work?

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore .

What is root reducer in Redux?

Redux uses a single root reducer function that accepts the current state (and an action) as input and returns a new state.


2 Answers

The Redux docs cover this topic in the section Structuring Reducers - Beyond combineReducers. Basically, you need to use more than just combineReducers to accomplish what you want. I also give an example of writing some custom reducer structuring logic in my recent blog post Practical Redux, Part 7: Form Change Handling, Data Editing, and Feature Reducers.

like image 146
markerikson Avatar answered Sep 30 '22 18:09

markerikson


After some refactoring I found that best is not to use combineReducers in this situation at all. Instead I structured my root reducer like so:

const App = (state = initialState, action) => {
  state = Object.assign({}, state)

  switch (action.type) {
    case OPEN_PAGE:
      state = openPage(state, action)
    case LOAD_MORE_ITEMS:
      state.pages.browse.numOfItems = loadMoreItems(state.pages.browse.numOfItems, action)
    case SET_FILTER:
      state.pages.browse.filter = setFilter(state.pages.browse.filter, action)
    case ADD_ITEM_TO_FAVORITES:
      state.favoriteItems = addItemToFavorites(state.favoriteItems, action)
    case ADD_ITEM_TO_BASKET:
      state.inBasketItems = addItemToBasket(state.inBasketItems, action)
  }

  return state
}

Maybe it would make sense to use combineReducers if any of reducers that work on particular part of state were more complicated, but it worked like this for me. I still kept some boilerplate in sub-reducers for readability purpose, like so:

const loadMoreItems = (state = initialState.pages.browse.numOfItems, action) => {
  switch (action.type) {
    case LOAD_MORE_ITEMS:
      return state = action.number
    default:
      return state
  }
}

So basically I keep the state initialization and action name since it makes it easier to understand what this reducer is all about.

like image 38
Aurimas Avatar answered Sep 30 '22 18:09

Aurimas