How do I add an element to array in reducer in Redux when the array does not yet exist?

redux array of objects
redux add item to array
redux add to array if not exists
redux update state object
redux reducer add to object
redux immer
redux remove an item from an array
redux update nested object

I have a code sandbox to demo an issue I am having with Redux and React.

https://codesandbox.io/s/reactredux-3edy8

Basically this reducer does not work:

const initialState = {
  byId: {}
};

function addReducer(state = initialState, action) {
  switch (action.type) {
    case "RECEIVE_DATA":
      return {
        ...state,
        byId: {
          ...state.byId,
          [action.payload.id]: [
            ...state.byId[action.payload.id],
            action.payload.data
          ]
        }
      };
    default:
      return state;
  }
}

export default addReducer;

here is the action:

import { RECEIVE_DATA } from "./actionTypes";

export function action() {
  return {
    type: RECEIVE_DATA,
    payload: {
      id: Math.floor(Math.random() * 2),
      data: Math.floor(Math.random() * 10000)
    }
  };
}

In my own app it throws an error like state.byId[action.payload.id] is not iterable which is true. But how do I push values to an array that does not yet exist because I do not know the id?

I thought the issue might be solved by changing the initialState or perhaps there is a function I am not aware of that allows me to either create an array or push to it.

Check if the array exists first. If it does, add a new element. If not, create a new array with one element (the new data from the action)

const initialState = {
  byId: {}
};

function addReducer(state = initialState, action) {
  switch (action.type) {
    case "RECEIVE_DATA":
      return {
        ...state,
        byId: {
          ...state.byId,
          [action.payload.id]: (
              state.byId[action.payload.id] ? [
              ...state.byId[action.payload.id],
              action.payload.data
            ] : [action.payload.data])
        }
      };
    default:
      return state;
  }
}

export default addReducer;

You can read more about ternary statements here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

Immutable Update Patterns, However, reducers will often need to use those basic operations in combination Defining a new variable does not create a new actual object - it only creates Normally, a Javascript array's contents are modified using mutative functions like push Updating one item in an array can be accomplished by using Array.map� The existing reducer, and the state that it manages, could be extended to add this capability, but that doesn’t feel like a good approach. The reducer and component are small and focussed units of functionality, I’d prefer to leave them that way. A better approach would be to add a new reducer that manages the state for a collection of

I am not sure but I think you need something like this

 function addReducer(state = initialState, action) {
      switch (action.type) {
        case "RECEIVE_DATA":
          return {
            ...state,
            byId: {
              ...state.byId,
              [action.payload.id]: 
                [action.payload.data]

            }
          };
        default:
          return state;
      }
    }

Applying redux reducers to arrays, In this blog post I'll take a look at how you can take a reducer and apply it function because the button clicks do not result in actions being dispatched. reducer, using the index to locate the correct item within the array of reducers to multiple state objects, hopefully this post will have been useful to you. Array.reduce is like a sister to Redux. If you aren’t yet familar with Array.reduce, here’s what’s up: JavaScript’s Array has a built-in function called reduce. (Technically I should be writing it as Array.prototype.reduce, because it is a function on array instances, not on the capital-A Array constructor.)

The answer to this problem lies in flattening the state. I am sure there are other ways to fix this problem, but I found this the cleanest.

Typically the byId property of state is created through flattening state per the guidelines in the docs

I take it one step further, making the byId property an Array instead of an Object. I move the id into the objects of the array like in this new sandbox: https://codesandbox.io/s/reactredux-zj1n4

I just have to remember the byId is now an array when I map the state to my components.

No functionality is lost and my byId field can now support multiple different ids if needed (e.g. if I had many to many relationships on the objects)

Here is the code:

in reducer

case "RECEIVE_DATA":
      return {
        ...state,
        byId: [...state.byId, action.payload.data]
      };

new action:

export function action() {
  return {
    type: RECEIVE_DATA,
    payload: {
      data: {
        id: Math.floor(Math.random() * 2),
        value: Math.floor(Math.random() * 10000)
      }
    }
  };
}

Actions and reducers: updating state � Human Redux, The Redux documentation on actions, for example, does not. will break in obvious ways because you're importing things that don't exist. Similarly, in Redux a reducer takes the starting state and an item to process, and return the new state. Note that just like the function we first passed to Array.prototype. reduce when� Redux Patterns: Add/Edit/Remove Objects in an Array implement a Redux-flavored store and reducer in a single React component without actually using Redux. I didn’t code out the logic in the

Immutability in React and Redux: The Complete Guide, JavaScript is not this extreme, but some languages don't allow mutation at all Certain Array operations in JS are immutable (meaning that they return a new It has been mutated. push (add an item to the end); pop (remove an item from the end) Redux requires that its reducers be pure functions. And like other reducers, combineReducers() does not create a new object if all of the reducers provided to it do not change state. # Note for ES6 Savvy Users Because combineReducers expects an object, we can put all top-level reducers into a separate file, export each reducer function, and use import * as reducers to get them as an object with

Redux: Avoiding Array Mutations with concat(), slice(), and spread , Learn how to avoid mutating arrays using concat(), slice(), and the ES6 array spread At first, I use the array push method to add a new item at the end of the array, Instead of push, I'm going to use the concat method, which does not modify� This is a question about state in Redux js. I have an array list in the state: { list: list } According to Redux document, I should not modify the state in the reducer. I want to append a new item to the list. Should I clone the list, or simply append the new item to the list:

Why you should use an object, and not an array, for lists in Redux , Using objects instead of arrays for lists of items in your state will give you a more robust code. Especially if How about adding to an object the same item twice? Nothing to They are NOT redux reducers or other kind of state creator. We have to assume that we don't know whether it already exists or not The articles listed in Prerequisite Concepts#Immutable Data Management give a number of good examples for how to perform basic update operations immutably, such as updating a field in an object or adding an item to the end of an array. However, reducers will often need to use those basic operations in combination to perform more complicated tasks.

Comments
  • So if, for example, your action's payload.id were 1, and your payload.data was 1000, what value would you expect state.byId.1 to contain?
  • state.byId["1"] would be ["1000"] if another action were to happen with { id: 1, data: 2000 } then state would be: { byId: { "1": ["1000", "2000"] } } However, I found the answer I believe... will type it up now.
  • Thank you, very nice alternative to what I ended up going with. If you're going to downvote though, you should leave a comment as to why. I believe my answer is a fine alternative, but if there is a reason why its not ok I would like to know.
  • It doesn't do what the question says
  • This will overwrite whatever data is already there. The idea is to append any new data to an existing array if it's there