@andrey_chirkin

Почему данные меняются в двух стейтах одновременно?

Добрый день! Я пытаюсь сделать таблицу с редактируемыми полями. Идея в том, что при нажатии на кнопку save данные из инпута должны сохраняться в таблице, а при нажатии на кнопку cancel данные в таблице не должны меняться. У меня проблема со стейтами contacts и contactsInput. Первый стейт нужен для того, чтобы выводить данные в таблицу. Второй для поля value в . При записи данных в один стейт, происходит запись и в другой стейт. Хотя, насколько я понимаю, общих ссылок у них нет. Заранее спасибо!
import React, {Fragment, useState} from 'react'

export default function ContentTable() {

	const data = [
		{
			"id": 1,
			"fullName": "Jenny Chan",
			"address": "3 waterfoot road",
			"phoneNumber": "333-962-7516",
			"email": "jenny.chan@email.com"
		},
		{
			"id": 2,
			"fullName": "Jessica warren",
			"address": "4 tall town",
			"phoneNumber": "011-211-7516",
			"email": "jessica.warren@email.com"
		},
		{
			"id": 3,
			"fullName": "Tony Frank",
			"address": "11 lesly road",
			"phoneNumber": "788-962-7516",
			"email": "tony.frank@email.com"
		},
		{
			"id": 4,
			"fullName": "Jeremy Clark",
			"address": "333 miltown manor",
			"phoneNumber": "011-962-111",
			"email": "jeremy.clark@email.com"
		},
		{
			"id": 5,
			"fullName": "Raymond Edwards",
			"address": "99 blue acres",
			"phoneNumber": "3231-962-7516",
			"email": "raymon.edwards@email.com"
		}
	]

	const [contacts, setContacts] = useState([...data])
	const [contactsInput, setContactsInput] = useState([...data])
	const [checkId, setCheckId] = useState(null)

	const handleChange = (index) => (
		(event) => {
			const {name, value} = event.target
			const contactsInputCopy = [...contactsInput]
			contactsInputCopy[index][name] = value
			console.log(index, name)
			console.log(contactsInputCopy[index][name])
			console.log(contacts[index][name])
			setContactsInput(contactsInputCopy)
		}
	)

	const handleSave = () => {
		setContacts([...contactsInput])
		setCheckId(null)
	}

	const handleCancel = (event) => {
		setCheckId(null)
	}

	return (
		<div className="tableContainer">
			<table>
				<thead>
					<tr>
						<th>Name</th>
						<th>Address</th>
						<th>Phone number</th>
						<th>email</th>
						<th>Action</th>
					</tr>
				</thead>
				<tbody>
				{contacts.map((contact, index) => (
					<Fragment key={`key:${index}`}>
						{checkId === contact.id ? (
							<tr>
								<td>
									<input type="text" name="fullName" value={contactsInput[index].fullName} onChange={handleChange(index)}/>
								</td>
								<td>
									<input type="text" name="address" value={contactsInput[index].address} onChange={handleChange(index)}/>
								</td>
								<td>
									<input type="text" name="phoneNumber" value={contactsInput[index].phoneNumber} onChange={handleChange(index)}/>
								</td>
								<td>
									<input type="text" name="email" value={contactsInput[index].email} onChange={handleChange(index)}/>
								</td>
								<td>
									<input type="button" value="Save" onClick={handleSave}/>
									<input type="button" value="Cancel" onClick={handleCancel}/>
								</td>
							</tr>
						) : (
							<tr>
								<td>{contact.fullName}</td>
								<td>{contact.address}</td>
								<td>{contact.phoneNumber}</td>
								<td>{contact.email}</td>
								<td>
									<input type="button" value="Edit" onClick={() => setCheckId(contact.id)}/>
								</td>
							</tr>
						)}
					</Fragment>
				))}
				</tbody>
			</table>
		</div>
	)

}
  • Вопрос задан
  • 79 просмотров
Решения вопроса 1
IwanQ
@IwanQ
Плохие времена часто дают прекрасные возможности
const copyArray = (array = []) => JSON.parse(JSON.stringify(array));

const [contacts, setContacts] = useState(copyArray(data));
const [contactsInput, setContactsInput] = useState(copyArray(data));


[...data] - это разворачивание массива. В данном случае оно бесполезно, потому что это массив не примитивов. Объекты копируются по ссылке, а не по значению.

Если бы в массиве были значения в виде примитивов, это бы сработало.

Я предложил самый простой способ, но вообще это не оптимально по производительности. Лучше делать это с помощью метода cloneDeep из библиотеки lodash.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Alexandroppolus
@Alexandroppolus
кодир
Внутри handleChange немного изменить строку:
contactsInputCopy[index] = { ...contactsInputCopy[index], [name]: value }


таким образом вместо изменения объекта создаешь новый
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы