wnoveno
wnoveno

Reputation: 546

Modifying a deep nested state in Redux

My reducer looks like this

const INITIAL_STATE = { map:[], routes:[], road:null};


export default function (state = INITIAL_STATE, action){
    switch(action.type){
        case TOGGLE_ROUTE_VISIBILITY : return { ...state, routes: action.payload };
            break;
        case SAVE_ROAD_ROUTE : return {...state, routes: action.payload };
            break;
    default:
        return state;
    }
}

and my action looks like this

export function toggleVisibility(id, routes){
    const i = _.findIndex(routes, o => { return o.id = id });
    routes[i].visible = !routes[i].visible;
    return {
        type: TOGGLE_ROUTE_VISIBILITY,
        payload: routes
    }
}

So my state looks like

state:{
    base:
        routes : [
           {id:1, visible:true},
           {id:2, visible:true},
        ]
}} 

The main problem is setting the data on the routes state. I have a feeling that my approach is incorrect and there's a proper way of saving the routes in the state and still be able to modify and save it.

Upvotes: 0

Views: 211

Answers (2)

Majky
Majky

Reputation: 2013

I prefer to keep actions simple and move all logic into reducers. There is no need to pass routes object into each action.

Here is simple example

const INITIAL_STATE = {map: [], routes: [], road: null};

export default function (state = INITIAL_STATE, action) {
    switch (action.type) {
        case TOGGLE_ROUTE_VISIBILITY :
            return Object.assign(state, {
                routes: state.routes.map(function (route) {
                    if (route.id === action.id) {
                        route.visible = !route.visible;
                    }
                    return route;
                })
            });
            break;
        case SAVE_ROAD_ROUTE:
            return Object.assign(state, {
                routes: [
                    ...state.routes,
                    {
                        id: action.id, // or just add some ID generator here
                        visible: true
                    }
                ]
            });
            break;
        default:
            return state;
    }
}

Action

export function toggleVisibility(id){
    return {
        type: TOGGLE_ROUTE_VISIBILITY,
        id: id
    }
}

Also have a look at Immutable.js which really helps in this scenario.

Upvotes: 1

JMM
JMM

Reputation: 26807

You should just pass the route ID in your action. You can use some kind of immutability helper to update the state in the reducer, or you can do it more manually. For example, using the React update add-on:

return update(state, {
  base: {
    routes: {
      [action.payload.routeId]: {
        visible: {
          $apply: function (visible) {
            return !visible;
          }
        }
      }
    }
  }
});

Upvotes: 0

Related Questions