Редактировать свойство в массиве объектов в react на основе идентификатора

У меня есть массив объектов, созданных в новом «Контекстном API» вроде этого ...

const reducer = (state, action) => {
    switch (action.type) {
        case "DELETE_CONTACT":
            return {
                ...state,
                contacts: state.contacts.filter(contact => {
                    return contact.id !== action.payload;
                })
            };
        default:
            return state;
    }
};

export class Provider extends Component {
    state = {
        contacts: [
            {
                id: 1,
                name: "John Doe",
                email: "jhon.doe@site.com",
                phone: "01027007024",
                show: false
            },
            {
                id: 2,
                name: "Adam Smith",
                email: "adam.smith@site.com",
                phone: "01027007024",
                show: false
            },
            {
                id: 3,
                name: "Mohammed Salah",
                email: "mohammed.salah@site.com",
                phone: "01027007024",
                show: false
            }
        ],
        dispatch: action => {
            this.setState(state => reducer(state, action));
        }
    };

    render() {
        return (
            <Context.Provider value={this.state}>
                {this.props.children}
            </Context.Provider>
        );
    }
}

Я хочу создать действие в «reducer», которое позволяет мне редактировать свойство «show» каждого контакта на основе его идентификатора, который я передам действию в качестве полезной нагрузки. Как я могу это сделать?

2
0
690
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете найти контакт, избежать мутации с помощью spread, установить новое значение show:

case "EDIT_CONTACT":
    const { id, show } = action.payload; // Assume id and show are in action.payload
    const contact = { ...state.contacts.find(c => c.id === id), show };
    return {
        ...state,
        contacts: [...state.contacts.filter(c => c.id !== id), contact]
    };

Если порядок имеет значение:

    const { id, show } = action.payload; 
    const contact = { ...state.contacts.find(c => c.id === id), show };
    const index = state.contacts.findIndex(c => c.id === id);
    return {
            ...state,
            contacts = [ ...state.contacts.slice(0, index), contact, ...state.contacts.slice(index + 1)];
    }

Что ж, это работает, но после редактирования свойства он помещает отредактированный объект в нижнюю часть массива.

Ruby 10.08.2018 15:22

И если я расставлю его вот так ... contacts: [contact, ...state.contacts.filter(c => c.id !== id)] поместит его в начало массива.

Ruby 10.08.2018 15:25

Спасибо за решение, оно работает, но я думаю, что решение @samee выглядит более элегантно.

Ruby 11.08.2018 12:11
Ответ принят как подходящий

Чтобы избежать мутации массива и сохранить позицию элемента при редактировании контакта, вы можете сделать это:

case "EDIT_CONTACT":
    const { id, show } = action.payload;
    const contact = { ...state.contacts.find(c => c.id === id), show };
    return {
       ...state,
       contacts: state.contacts.map(c => {return (c.id !== id) ? c : contact;})        
    };

Другие вопросы по теме