본 글은 인프런 강의 ≪React 완벽 마스터: 기초 개념부터 린캔버스 프로젝트까지≫를 기반으로 작성 되었습니다. 😉
객체 업데이트 하기
⛔️ React State가 가진 객체를 직접 복사하면 안된다.
객체를 업데이트하고 싶을 때는 반드시 새로운 객체를 생성해 복사본을 사용해야 한다.
- 새로운 객체를 생성할 때 전개(
...
) 구문을 활용해야 함 - 전개(
...
) 구문은 한 레벨 깊이만 복사함에 주의- 중첩된 프로퍼티를 업데이트하고 싶다면 한 번 이상 사용해야 한다는 의미
만약에 form
을 업데이트 해야 한다면, 아래와 같이 전개 구문을 활용해 복사본을 생성해 업데이트 한다.
const [form, setForm] = useState({
title: 'title',
desc: 'desc'
})
const handleChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value
})
}
중첩 객체 업데이트(with Immer)
const [form, setForm] = useState({
title: 'title',
desc: 'desc',
info: {
level: 1,
skill: 'skill'
}
})
위와 같이 중첩 객체를 이용하는 State가 있다면, form
를 한 번 이상 사용해야만 중첩 객체를 업데이트 할 수 있을 것이다.
const handleSkillChange = (e) => {
setForm({
...form,
info: {
...form.info, // 여기서 한 번 이상 사용됨
skill: e.target.value // 그래야 업데이트할 수 있음
}
})
}
이를 user-immer
라이브러리를 통해 간결하게 리팩토링할 수 있다.
npm i user-immer
const [form, updateForm] = useImmer({
title: 'title',
desc: 'desc',
info: {
level: 1,
skill: 'skill'
}
})
const handleChange = (e) => {
updateForm(draft => {
draft[e.target.name] = e.target.value
})
}
const handleSkillChange = (e) => {
updateForm(draft => {
draft.info.skill = e.target.value
})
}
배열 업데이트 하기
배열은 변경 가능하지만, State로 저장할 때에는 변경할 수 없어야 한다. 객체와 마찬가지로, 업데이트할 때는 새 배열을 생성(혹은 기존 배열의 복사본을 생성)한 뒤, 새 배열을 State로 두어 업데이트해야 한다.
(2)
에서 원본 배열을 수정하지 않는 Array API를 알아야 함
const [todos, setTodos] = useState([
{ id: 0, label: 'Hello React!' }
])
const [todoText, setTodoText] = useState('')
const handleChangeTodoText = (e) => {
setTodoText(e.target.value)
}
cosnt handleAddTodo = (e) => {
const nextId = todos.length
todos.push({ id: nextId, label: todoText })
}
위 코드는 동작할 것이다. 그러나 핸들러가 todos
배열의 상태를 직접적으로 변경하기 때문에 동일 기능을 하는 새로운 컴포넌트에서도 이 변경을 감지해 리렌더링될 것이다. 이는 각각 컴포넌트의 상태가 불변하지 않음을 의미한다.
즉, todos
에 아이템을 추가하는 A, B 두 개의 컴포넌트가 있다면 B에서 일어난 변경이 A에도 영향을 준다는 것이다.
컴포넌트는 항상 순수해야 하기 때문에, 같은 컴포넌트여도 독립적인 상태를 갖고 있어야 불변하다. 따라서 배열의 상태를 업데이트 할 때는 위에서 말했듯 새 배열을 생성해야만 한다.
const handleAddTodo = (e) => {
const nextId = todos.length
setTodos([
...todos, // 전개 구문으로 새 배열을 생성
{ id: nextId, text: todoText } // 그 뒤에 새 요소를 추가
])
}
최신 Array API로 업데이트 하기
💡 2023년 7월부터 이 기능은 최신 기기 및 브라우저 버전에서 작동한다.
- Array.prototype.toSorted
- Array.prototype.toReversed
- Array.prototype.toSpliced
- Array.prototype.with
위 기능들은 모두 원본 배열을 변경하지 않고 새로운 배열을 반환하는 점에서 불변성을 유지하는 코드를 작성할 때 유용하다.(4)
References.
- (1) 객체 State 업데이트하기
- (2) 배열 State 업데이트하기
- (3) KeyPress Event
- (4) Array.prototype.toSorted()