https://react.dev/learn/choosing-the-state-structure 를 읽고 정리한다.

 

state를 잘 구성하면 수정 및 디버깅하기 용이한 컴포넌트를 만들 수 있다.

state 구성 원칙

이 원칙은 실수없이 상태를 업데이트하는 것이 목표이다. 이는 데이터베이스 구조를 정규화하여 버그 가능성을 줄이는 방법과 유사하다.

즉, 중복을 줄이면 모든 부분이 동기화 상태를 유지하는 데 도움이 된다.

 

1. 연관된 상태를 묶어라

항상 두 개 이상의 상태 변수를 동시에 업데이트 하는 경우, 단일 상태 변수로 병합해라.

 

state를 object 또는 array로 사용하는 경우는 얼마나 많은 상태가 필요한지 모르는 경우에 사용한다. 예를 들어 사용자가 사용자 정의 필드를 추가할 수 있는 양식이 있는 경우, 사용자가 얼만큼 추가할지 예상할 수 없으므로 이때 유용하게 사용된다.

state를 object로 만들 경우, 한 field만 업데이트할 수 없다.
이를 해결할 수 있는 방법은 아래와 같다.
1. `...`을 사용해 기존 상태를 펼친 후, 업데이트할 field만 재정의하는 방식으로 사용할 수는 있다. setObject({...object, x: 100 })
2. object로 된 변수를 두 개로 분리한 후 따로 업데이트 할 수 있도록 한다. setX(100)

2. 서로 반대되는 상태를 만들지 마라

서로 반대되는 상태를 만들면 실수가 생길 수 있다.

 

예를 들어, isSending, isSent 상태 변수를 사용한 호텔 피드백 양식이 있다고 하자.

이 코드는 isSending, isSent가 동시에 같은 값을 가질 수 없다. 또한 두 상태를 같이 세팅하는 것을 잊어버리면 버그가 발생하기 쉽다.

 

따라서 isSending, isSent가 동시에 같은 값을 가질 수 없으므로, 3가지 유효한 상태를 묶은 하나의 상태 변수를 사용하는 것이 좋다.

  • typing(inital), sending, sent

3. 불필요한 상태를 만들지 마라

렌더링시 컴포넌트의 prop 또는 state 변수에서 계산할 수 있는 정보는 state로 만들지 마라.

 

Deep Dive : state에 props를 미러링하면 안된다.

여기서는 color state 변수가 messasgeColor prop으로 초기화된다.
function Message({ messageColor }) {
  const [color, setColor] = useState(messageColor);​

 

state는 첫번째 렌더링 중에만 초기화된다. 따라서 중간에 상위 컴포넌트에서 다른 값을 전달하면 이를 미러링한 state값이 업데이트되지 않는다.

이때문에 state 변수를 prop으로 미러링하면 혼동을 일으킬 수 있다.
대신 messasgeColor prop은 코드에서 직접 사용해야한다.
function Message({ messageColor }) {
  const color = messageColor;​

 

만약, 특정 prop에 대한 모든 업데이트를 무시하고 싶으면 props를 state로 미러링해도 된다. 이 때, 규칙에 따라 prop 의 이름을 initial, default를 사용해 업데이트가 무시된다는 것을 표현해라.

4. 중복된 상태를 만들지 마라

여러 state 변수 사이나 중첩된 개체 내에서 동일한 데이터가 중복되는 경우 동기화를 유지하기가 어렵다. 가능하면 중복을 줄이자.

특히 선택같은 경우, 개체 자체가 아닌 ID 또는 인덱스로 상태를 유지해라.

5. 깊게 중첩된 상태를 만들지 마라

중첩된 상태는 변경된 부분외에도 중첩되어있는 모든 데이터를 업데이트 해야하기 때문에 어렵다. 가능하면 flat한 방법으로 상태를 구성하라.

flat하게 만들면 상태를 더 쉽게 업데이트할 수 있으며 중첩된 개체의 다른 부분에 중복이 없는지 확인하는 데 도움이 된다.

 

예를 들어, 아래와 같은 중첩된 객체가 있다고 하자.

여기서 하나의 장소를 제거하는 동작을 추가하려면 동작이 실행될 때마다 전체 상위 장소 체인을 복사해야한다.

 

이를 평평하게 만드려면 각 장소마다 ID와 정보를 따로 가지고, 추가로 하위 장소 ID의 배열을 사용해 매핑을 하면 된다.(마치 데이터베이스 테이블 처럼)

 

이렇게 되면 중첩 항목 업데이트가 더 쉬워집니다.

이 상태에서 하나의 장소를 제거하는 동작을 추가하려면 두 가지 상태만 업데이트하면 된다.

  • 상위 장소에서 childIds에 제거하려는 id를 제거
  • 루트에서 상위 장소의 업데이트된 버전이 포함되어야한다.

따라서 아래와 같이 수행할 수 있다.

 

 

 

+ Recent posts