Заменить элемент в массиве новым значением, используя отправку в 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;