Search code examples
javascriptarraysreactjsreduxdata-structures

Remove value from an array nested in an object also nested in an array


I have a problem with my code. I currently have some data like the one below;

 users: [
    {
      name: 'bolu',
      features: ['Tall'],
    },
    {
      name: 'cam',
      features: ['Bearded', 'Short'],
    },
  ],
};

What I am trying to do is delete/remove a single feature - for example if I pass in 'short' into my redux action. I'd like for it (the 'Short' text) to be removed from the features array. I currently have my redux action set up this way:

export interface UsersDataState {
  name: string,
  features: Array<string>,
}

export interface UsersState {
  users: UsersDataState[];
}

const initialState: UsersState = {
  users: [],
};

    export const usersSlice = createSlice({
      name: 'users',
      initialState,
      reducers: {
        removeUser: (state, action: PayloadAction<string>) => {
          const removedUsers = state.users.filter((user) => user.features.indexOf(action.payload));
          state.users = removedUsers;
        },
       },
   });

So here I am passing in the value in (action.payload is the value being passed in). When this action is dispatched, I want to remove just the word that is passed in from the features array. I hope this is clearer now.

This doesn't work for some reason and I am unable to figure out why. Any help would be appreciated please, thank you.


Solution

    1. Your code doesn't match your state structure. Replace traits with users, and values with features.

    2. It looks like that's a part of a reducer, not an action (which is an object, not a function).

    3. You should be returning a new state from the reducer.

    4. Given your update the function should be called removeFeature.

    So, I've corrected a few bits of your code based on what I remember from Redux. Note: contrived example.

    // State
    const state={users:[{name:"joe",features:["Mean","Short"]},{name:"bolu",features:["Tall"]},{name:"cam",features:["Bearded","Short"]}]};
    
    // The reducer accepts a state, and an action
    function reducer(state, action) {
    
      // We destructure the type, and payload, from the action object
      const { type, payload } = action;
    
      // Depending on the type...
      switch (type) {
    
        case 'removeFeature': {
          
          // `map` over the users (we return a new state array)
          return state.users.map(user => {
            
            // `filter` out the feature elements
            // that match the payload
            const updatedFeatures = user.features.filter(feature => {
              return feature !== payload;
            });
            
            // Return a new updated object
            return { ...user, features: updatedFeatures };
          
          });
        
        }
    
        default: return state;
    
      }
    
    }
    
    const updatedState = reducer(state, {
      type: 'removeFeature',
      payload: 'Short'
    });
    
    console.log(updatedState);