Заменить элемент в массиве новым значением, используя отправку в React

У меня есть исходный массив, в который можно добавлять и удалять, проблем нет..

const initialItems = [
    {
        id: Date.now(),
        text: 'Get milk',
    },
    {
        id: Date.now(),
        text: 'Get eggs',
    },
]

..но я пытаюсь понять, как эффективно редактировать текст одного из элементов с помощью функции отправки.

Моя депеша выглядит так:

const editItemHandler = () => {
    dispatch({
        type: 'EDIT_ITEM',
        id: Date.now(),
        text: itemInputRef.current.value,
        index,
    })
}

Которая просто передает значение ввода

<input
    autoFocus
    type='text'
    ref={itemInputRef}
    onKeyDown={(e) => {
        if (e.key === 'Escape') {
            setToggle(!toggle)
        }
        if (e.key === 'Enter') {
            // Dispatch
            editItemHandler()
            setToggle(!toggle)
        }
    }}
/>

Мой файл редуктора выглядит так:

const itemReducer = (state, action) => {
    switch (action.type) {
        case 'ADD_ITEM': {
            return [
                ...state,
                {
                    id: action.id,
                    text: action.text,
                },
            ]
        }
        case 'EDIT_ITEM': {
            // Attempt 1
            return [...state.splice((item, index) => index, 1, action.text)]
            // Attempt 2
            return [
                ...state.filter((item, index) => index !== action.index),
                {
                    id: action.id,
                    text: action.text,
                },
           ]
        }
        case 'DELETE_ITEM': {
            return [...state.filter((item, index) => index !== action.index)]
        }
        default: {
            return state
        }
    }
}

export default itemReducer

Я прокомментировал 2 подхода, которые я уже пробовал в типе EDIT_ITEM.

Подход 1 просто удаляет элемент и добавляет новый, хотя и в нижней части массива, а это не то, что я хочу, поэтому мне пришлось бы попытаться изменить порядок после этого.

Подход 2 использует сплайсинг, который, как я думал, подойдет для замены элемента с указанным значением. Однако все, что он возвращает, - это ТОЛЬКО "отредактированный" с исходным текстом (то есть даже не отредактированный) и удаляет все остальное.

Как я использую эту функцию неправильно или есть лучший подход к редактированию элемента на месте? Я явно делаю что-то не так, но не могу понять, что именно. Я искал и пробовал различные подходы, но безрезультатно.

В идеале я бы хотел, чтобы элемент также имел тот же идентификатор, что и раньше, поэтому как сохранить это было бы плюсом.

1 ответ

Решение

Чтобы обновить элемент в массиве, у вас есть несколько вариантов:

case 'EDIT_ITEM': {
    // using map
    return state.map((item, i) => 
                    i === action.index ? { id: action.id, text: action.text } : item
    // using slice
    return [
      ...state.slice(0, action.index),
      { id: action.id, text: action.text },
      ...state.slice(action.index+1)
    ]

Это неправильное использование splice

return [...state.splice((item, index) => index, 1, action.text)]

потому что splice возвращает массив, содержащий удаленные элементы, и не принимает функцию в качестве первого аргумента, а принимает индекс, с которого следует начать изменение массива.

правильный способ сращивания:

case 'EDIT_ITEM': {
    // using splice
    let newState = [ ...state ]
    newState.splice(action.index, 1, { id: action.id, text: action.text })
    // or you can directly do
    newState[action.index] = { id: action.id, text: action.text }
    // and return the new state
    return newState;
Другие вопросы по тегам