DouzeBri DouzeBra
DouzeBri DouzeBra

Reputation: 127

React Redux - Issue removing an item

I'm working on implementing beautiful-dnd in my react project.

I have the following data:

const initialData = {
        users: {
            'user-1': { id: 'user-1', name: 'John'},
            'user-2': { id: 'user-2', name: 'Patrick'},
            'user-3': { id: 'user-3', name: 'Malorie'},
            'user-4': { id: 'user-4', name: 'Eric'},
            'user-5': { id: 'user-5', name: 'Bob'},
            'user-6': { id: 'user-6', name: 'Blob'}
        },
        areas: {
            'area-0': {
                id: 'area-0',
                title: 'Main Area',
                userIds: ['user-1', 'user-2', 'user-3', 'user-4', 'user-5', 'user-6']
            },
            'area-1': {
                id: 'area-1',
                title: 'Area 1',
                userIds: []
            },
            'area-2': {
                id: 'area-2',
                title: 'Area 2',
                userIds: []
            }
        },
        areaOrder: ['area-0', 'area-1', 'area-2'],
    }

In the reducer, I try to remove one of the users this way:

case REMOVE_USER_ACTION:
    return {
        ...state,
        users: [ ...state.users.filter(user => user !== action.id) ]
    }

I'm getting this error:

TypeError: e.users.filter is not a function or its return value is not iterable

I searched for this error, but I'm unable to find a comparable scenario and how to fix this issue.

Upvotes: 1

Views: 52

Answers (3)

Nguyễn Văn Phong
Nguyễn Văn Phong

Reputation: 14228

TypeError: e.users.filter is not a function or its return value is not iterable

It means that users is not an array, it's object instead.

So you can get the filtered users in this way:

const users = {'user-1':{id:'user-1',name:'John'},'user-2':{id:'user-2',name:'Patrick'},'user-3':{id:'user-3',name:'Malorie'},'user-4':{id:'user-4',name:'Eric'},'user-5':{id:'user-5',name:'Bob'},'user-6':{id:'user-6',name:'Blob'}};

const actionId = "user-1";
const filteredUsers = Object.entries(users).filter(([key, value]) => value.id != actionId);
console.log(Object.fromEntries(filteredUsers));

As a result, your REMOVE_USER_ACTION looks like

case REMOVE_USER_ACTION:
    return {
        ...state,
        users: filteredUsers
    }

However, you should change users type from object to array in terms of performance, meaningful name & clean code.

const users = [{ id: 'user-1', name: 'John'},
         { id: 'user-2', name: 'Patrick'},
         { id: 'user-3', name: 'Malorie'},
         { id: 'user-4', name: 'Eric'},
         { id: 'user-5', name: 'Bob'},
         { id: 'user-6', name: 'Blob'}
       ];
       
const actionId = "user-1";
const filteredUsers = users.filter(item => item.id != actionId);
console.log(filteredUsers);

Upvotes: 2

Olivier Boissé
Olivier Boissé

Reputation: 18183

users is an object, not an array, so you can't iterate over it

Here is a possible solution using Object.entries

case REMOVE_USER_ACTION:
  return {
    ...state,
    users: Object.entries(state.users).reduce((acc, [key, value]) => {
      if (key !== action.id) {
        acc[key] = value;
      }
      return acc;
    }, {})
  }

Upvotes: 1

Leomar Amiel
Leomar Amiel

Reputation: 506

Can't filter the state.users if your data is an object. It's either you change the initialData shape or if it's really like that, then you'd have to do some way to delete a key from your object.

case REMOVE_USER_ACTION:
    const users = { ...state.users };
    delete users[action.id];
    return {
        ...state,
        users,
    }

Upvotes: 1

Related Questions