Redux reducer with object.assign creates key inside a top key with the same name

redux multiple reducers same state
combine reducers
redux update state from another reducer
redux actions
redux multiple reducers same action
the redux store should only be updated by:
react-redux reducer example
redux reducers best practices

I'm trying to move from the simple example I've learnt on Medium about Redux to properly modify immutable state with object.assign or the spread operator. However, after I've tried this it creates a key in the original state key with the same name. F.e. I had a state key searchPage: 1 and after converting the reducer I've got searchPage: {searchPage: 1}. I bet it's silly, but I did it according to the Redux docs (I only assume). I've tried object.assign and the spread operator, which have the same results. Here is my old reducer:

export function searchPage(state = 1, action) {
  switch (action.type) {
    case 'SET_SEARCH_PAGE':
      return action.searchPage

    default:
      return state
  }
}

and the new with spread operator:

export function searchPage(state = 1, action) {
  switch (action.type) {
    case 'SET_SEARCH_PAGE':
      return { ...state, searchPage: action.searchPage }

    default:
      return state
  }
}

update Now, I'm using an initialState object to set initial state for all reducers to an object as a default. However, the spread operator syntax now does exactly the same as before, i.e. inserts the initial state key inside the searchPage key, so I still end up with object inside my searchPage key instead of a number. Here's the updated code, I have no idea if I go in the right direction:

const initialState = {
  posts: [],
  postsHasErrored: false,
  postsIsLoading: false,
  searchString: '',
  searchCategories: [],
  searchPage: 10
}

export function searchString(state = initialState.searchString, action) {
  console.log(state)
  switch (action.type) {
    case 'SET_SEARCH_STRING':
      return action.searchString

    default:
      return state
  }
}

export function searchCategories(state = initialState.searchCategories, action) {
  switch (action.type) {
    case 'SET_SEARCH_CATEGORIES':
      return action.searchCategories

    default:
      return state
  }
}

export function searchPage(state = initialState.searchPage, action) {
  switch (action.type) {
    case 'SET_SEARCH_PAGE':
      return { ...state, searchPage: action.searchPage }

    default:
      return state
  }
}

It depends on what your action.searchPage value. I think it's an object. Once go through debugging for action object.

try like this

export function searchPage(state = {}, action) {
  switch (action.type) {
    case 'SET_SEARCH_PAGE':
      return { ...state, searchPage: action.searchPage };

    default:
      return state
  }
}

Reducers, Keep every entity in an object stored with an ID as a key, and use IDs to Note that: We don't mutate the state . We create a copy with Object.assign() . Because combineReducers expects an object, we can put all top-level reducers into a use import * as reducers to get them as an object with their names as the keys:. All combineReducers() does is generate a function that calls your reducers with the slices of state selected according to their keys, and combines their results into a single object again. It's not magic.

I had this issue as well. By researching online I've seen people saying you just needed to initialize your state empty in actions, and while that helped me while I was using only one item from state, it went downhill when I needed two.

This new error happened at my own component file, at mapStateToProps. Because this works...

const mapStateToProps = state => (
   state.posts
);

But this doesn't...

const mapStateToProps = state => (
   state.posts, state.comments
);

So I'd end up writing...

const mapStateToProps = state => ({
   posts: state.posts,
   comments: state.comments
});

Which would duplicate the key name, causing the arrays to be posts.posts and comments.comments. After trying many different syntaxes, I finally found what works:

function mapStateToProps(state){
  const { posts } = state.posts
  const { comments } = state.comments
  return { posts, comments}
}

Hope it helps someone!

Using combineReducers, Multiple slice reducers can respond to the same action, independently update their own combineReducers takes an object full of slice reducer functions, and creates a slice reducer object will define the naming of the keys in the output state object. defaultState, // key name same as the carefully renamed default export. Redux: Avoiding Object Mutations with Object.assign () and spread. Dan Abramov. React. 0.14 - 16. Redux. 3 - 4. Learn how to use Object.assign () and the spread operator proposed for ES7 to avoid mutating objects.

Just got an update of this old issue. Now, when I look at it it's obvious. In the reducer, when initializing state = initialState.searchPage it should just be state = initialState. And the whole reducer should be just one function so that I can utilize the use case for the switch statement.

Refactoring Reducers Example, Structuring Reducers > Refactoring Reducers: Examples of ways to refactor reducer logic. trying to update a specific item in an array that we could extract to a function: to Object.assign to ensure we correctly copy data instead of mutating to use a function that creates a lookup table of action types to case functions. @matisoffn: that's one of the reasons why you are encouraged to keep your Redux state as flat as possible.Writing "manual" nested update code gets really ugly.. FYI, I have a work-in-progress set of new pages for the Redux docs on "Structuring Reducers", and the page on Immutable Update Patterns discusses this a bit.

Actions and reducers: updating state · Human Redux, In Redux we say that actions (reports) are "dispatched" to the store to let it know If you find yourself creating actions that sound like a a function call like It takes an object where each key is a name, each value is a reducer function, and it use Object spread syntax to accomplish the // same thing as Object.assign const  If you do use this, it may help to add some comments to your code that explain your reducers are using Redux Toolkit and Immer. In addition, Redux Toolkit's createSlice utility will auto-generate action creators and action types based on the reducer functions you provide, with the same Immer-powered update capabilities inside.

Understanding How Reducers are Used in Redux, The reducer function makes use of the initial state of the application and something An action is an object that contains two keys and their values. const action = { type: 'NEW_CONTACT', name: 'John Doe', location: 'Lagos In the above example, we made use of the Object.assign() to make sure that  Create a function called createFluxStore(reducer) that creates a Flux store compatible with your existing app from a reducer function. Internally it might look similar to createStore implementation from Redux. Its dispatch handler should just call the reducer for any action, store the next state, and emit change.

Deeply Nested Objects and Redux, With deeply nested objects, the workload (of both human and to the Redux state, this applies in general to React's immutable state and Redux State Best Practices allIds essentially gives us the list of keys in order so that we know in In the following example, we have created another reducer at the  In particular, the common suggested pattern is to have a separate sub-reducer function that is responsible for managing updates to a particular slice of state at a specific key. The combineReducers() that comes with Redux is one of the many possible ways to achieve this.

Comments
  • Your old and new reducers implement different behaviors. In first case, all state is simple number, so you replace it to new number. In second case, you always create new object by Object.assign, to which your spread operator is transpiled.
  • How do I get over it then? Should I leave it as is or change my initial state for the whole application? The problem I'm having is that my React app doesn't re-render after f.e. searchPage is updated in the state, so I thought it's because of the way I'm modifying state. Here's more code of my app stackoverflow.com/questions/45256875/…
  • action.searchPage is always an int number.
  • @MateuszMysiak Are you sure for that? If so initialise your state with an empty object as in updated answer.
  • I've done that. Still the same result. In my app state there is searchPage: {searchPage: 1} instead of searchPage: 1