오류 없이 상태를 쉽게 업데이트하기 위해서 공식 문서에서는 다음 원칙을 제시한다. 이 글을 읽기 전까지 나는 막연히 렌더링에 영향을 주는 값은 모조리 state로 관리하는 줄 알았다. 그러면서 실제로 모순되거나, 불필요한 state를 사용한 경험이 있다. state 구조화 원칙은 그런 문제가 될 요소들을 제거하는 방향으로 구성되어 있다.
리액트의 렌더링 로직을 잘 이해했다면 state 구조화 원칙 역시 쉽게 납득할 수 있을 것이다.
두 개 이상의 state를 항상 동시에 업데이트하는 경우 항상 동기화될 수 있도록 단일 state 변수로 병합해야 한다.
ex. 마우스 커서의 x, y 좌표 등은 하나의 객체 state로 관리
여러 state가 서로 모순되고 불일치하는 경우 피해야 한다.
ex. isSent와 isSending state가 있을 때 isSent가 true이면서 isSending도 true인 경우는 존재할 수 없다. 다시 말해 모순된다.
→ typing, sending, sent 세 가지 유효한 상태 중 하나를 가질 수 있는 status state로 관리
→ 그 후 아래와 같이 각각의 상태에 대한 상수를 선언하면 서로 동기화되지 않을 우려를 지우면서 가독성을 높일 수 있다.
const isSending = status === 'sending';
const isSent = status === 'sent';
// bad
function Message({ messageColor }) {
const [color, setColor] = useState(messageColor);
// good
function Message({ messageColor }) {
const color = messageColor;
initial 또는 default로 시작하여 새 값이 무시됨을 명시한다. function Message({ initialColor }) {
// The `color` state variable holds the *first* value of `initialColor`.
// Further changes to the `initialColor` prop are ignored.
const [color, setColor] = useState(initialColor);
배열의 어떤 한 원소에 대한 state를 생성하는 대신, 배열 요소의 고유한 값(id 등)에 대한 state를 생성하여 해당 state로 배열에 접근하는 것이 좋다.
그 원소에 대한 정보가 중복되는 경우, 두 가지 정보를 모두 업데이트하는 것보다 원본 state만 변경하는 것이 효율적이고 더 안전하기 때문이다.
ex. const [items, setItems] = useState([...]);가 선언되어 있을 때,
const [selectedItem, setSelectedItem] = useState(items[0]); 대신
const [selectedIndex, setSelectedIndex] = useState(0);을 사용하는 게 좋다.
immer 라이브러리를 사용할 수 있다.immer 라이브러리를 사용하면 객체의 값을 직접 수정하는 것처럼 간단하게 코드를 작성할 수 있다. export const initialTravelPlan = {
id: 0,
title: '(Root)',
childPlaces: [{
id: 1,
title: 'Earth',
childPlaces: [{
id: 2,
title: 'Africa',
childPlaces: [{
id: 3,
title: 'Botswana',
childPlaces: []
}, {
id: 4,
title: 'Egypt',
childPlaces: []
},
...
],
...
};
export const initialTravelPlan = {
0: {
id: 0,
title: '(Root)',
childIds: [1, 42, 46],
},
1: {
id: 1,
title: 'Earth',
childIds: [2, 10, 19, 26, 34]
},
2: {
id: 2,
title: 'Africa',
childIds: [3, 4, 5, 6 , 7, 8, 9]
},
3: {
id: 3,
title: 'Botswana',
childIds: []
},
...
};