1

I've been breaking my head for a week or something with this !!

My redux state looks similar to this

{
  data: {
      chunk_1: {
        deep: {
         message: "Hi"
        }
      },
      chunk_2: {
        something: {
         something_else: {...}
        }
      },
     ... + more
  },
  meta: {
   session: {...},
   loading: true (or false)
  }
}

I have an array of keys like ["path", "to", "node"] and some data which the last node of my deeply nested state object should be replaced with, in my action.payload.

Clearly I can't use spread operator as shown in the docs (coz, my keys array is dynamic and can change both in values and in length). I already tried using Immutable.js but in vain.. Here's my code

// Importing modules ------ 
import {fromJS} from "immutable";

// Initializing State --------- 
const InitialState = fromJS({ // Immutable.Map() doesn't work either
    data: { ... },
    meta: {
        session: {
            user: {},
        },
        loading: false,
        error: "",
    },
});

// Redux Root Reducer ------------
function StoreReducer(state = InitialState, action) {
  
  switch (action.type) {
    case START_LOADING: 
    return state.setIn(["meta"], (x) => {
                return { ...x, loading: true };
    });

    case ADD_DATA: {
      const keys = action.payload.keys; // This is a valid array of keys
      return state.updateIn(keys, () => action.payload); // setIn doesn't work either
    }
  
}

Error I get..

Uncaught TypeError: state.setIn (or state.updateIn) is not a function
    at StoreReducer (reducers.js:33:1)
    at k (<anonymous>:2235:16)
    at D (<anonymous>:2251:13)
    at <anonymous>:2464:20
    at Object.dispatch (redux.js:288:1)
    at e (<anonymous>:2494:20)
    at serializableStateInvariantMiddleware.ts:172:1
    at index.js:20:1
    at Object.dispatch (immutableStateInvariantMiddleware.ts:258:1)
    at Object.dispatch (<anonymous>:3665:80)

What I want ?

The correct way to update my redux state (deeply nested object) with a array containing the keys.

  • That's actually a great reason to migrate to redux toolkit. No need to use immutablejs or deeply clone the entire state for purposes like yours. You could simply loop over your array of keys and save the current level of nesting in a let variable. As soon as you have reached the last key, mutate the parent node with `currentLevel[lastKeyOfArray] = data` and you're done. – timotgl Aug 15 '22 at 19:02

2 Answers2

2

Please note that you are using an incredibly outdated style of Redux. We are not recommending hand-written switch..case reducers or the immutable library since 2019. Instead, you should be using the official Redux Toolkit with createSlice, which allows you to just write mutating logic in your case reducers (and thus also just using any helper library if you want to use one).

Please read Why Redux Toolkit is how to use Redux today.

phry
  • 35,762
  • 5
  • 67
  • 81
  • Thanks a lot for this answer, all these years I wondered why people complain and write such ugly reducers - you made me realize that my predecessor were ahead of their time and there is an "official" solution for their `createReducer` utility – dube Aug 17 '22 at 07:34
  • Switched to RTK and now everything works smoothly .... Thank you so much – Hard Code Programmer Aug 19 '22 at 08:03
0

you could use something like that:

    import { merge, set } from 'lodash';

    export default createReducer(initialState, {
...
      [updateSettingsByPath]: (state, action) => {
        const {
          payload: { path, value },
        } = action;
        const newState = merge({}, state);
        set(newState, path, value);
        return newState;   },
...}
  • Some feedback from a RTK maintainer: Usually you should use `createSlice`, not `createReducer`. You should also always use the `builder` notation for `createReducer` or `extraReducers` as we will remove the object notation in a future version. Also, you don't need a `newState` and return it here - you can just `set(state, path, value);` in Redux Toolkit's `createSlice` or `createReducer`. – phry Aug 15 '22 at 15:01