모든 기록

React 상태, 작게 나누고 명확하게

화면에 필요한 상태는 어디까지일까요? 원본 데이터와 파생 값을 구분하며 인터페이스를 단순하게 만듭니다.

블로그 구성을 보여주는 예제 글입니다.

컨트롤 하나를 더했을 뿐인데 여러 값이 함께 바뀌어야 한다면, 상태의 모양을 다시 살펴볼 때입니다. 화면에 보이는 모든 값을 상태로 저장하면 서로 맞춰야 할 값도 늘어납니다.

작은 차트를 예로 들어 원본 데이터와 사용자의 선택, 그리고 화면에 필요한 계산 결과를 구분해 보겠습니다.

저장할 값과 계산할 값

30일치 방문 기록이 있고, 사용자는 최근 7일 또는 30일을 선택할 수 있습니다. 실제로 저장해야 할 상태는 선택한 기간입니다. 화면에 표시할 데이터는 그 기간에서 계산할 수 있습니다.

const [period, setPeriod] = useState<7 | 30>(7);
const visibleData = records.slice(-period);

return (
  <section>
    <button onClick={() => setPeriod(7)}>최근 7일</button>
    <button onClick={() => setPeriod(30)}>최근 30일</button>
    <Chart data={visibleData} />
  </section>
);

선택한 기간과 표시할 데이터를 각각 상태로 저장하면 두 값이 어긋날 여지가 생깁니다. 계산으로 구할 수 있는 값을 따로 저장하지 않으면 동기화 문제도 줄어듭니다.

상태는 사용하는 곳 가까이에

이 차트의 기간을 다른 페이지에서도 알아야 할까요? 그렇지 않다면 전역 저장소를 도입할 이유는 아직 없습니다. 해당 화면이 소유한 로컬 상태만으로 충분합니다.

상태를 가까이에 두면 다음 질문에 답하기 쉬워집니다.

  • 어떤 사용자 입력이 이 값을 바꾸는가?
  • 값이 바뀌면 화면의 어느 부분이 달라지는가?
  • 컴포넌트가 사라지면 이 값을 유지해야 하는가?

목록을 바꿀 때 주의할 점

여러 지표를 표시하거나 숨길 때는 기존 배열이나 객체를 직접 변경하기보다 새 값을 반환합니다. 이전 값에 따라 다음 값을 만들 때는 함수형 업데이트가 흐름을 분명하게 해줍니다.

const [visible, setVisible] = useState({ visitors: true });

function toggleVisitors() {
  setVisible(previous => ({
    ...previous,
    visitors: !previous.visitors,
  }));
}

작은 상태에서 시작하기

복잡한 도구가 필요해지는 순간은 분명히 있습니다. 다만 처음에는 입력과 화면의 관계를 설명할 수 있는 가장 작은 상태부터 시작해 보세요. 관계가 명확하면 나중에 상태의 범위를 넓히기도 수월합니다.

이 사이트의 차트 데모는 기간과 지표 선택을 로컬 상태로 관리합니다. 컨트롤을 바꾸면 그래프와 표가 같은 계산 결과를 함께 사용합니다.

오늘의 작은 배움을 기록해 두세요.
← 글 목록으로 돌아가기읽었다면, 직접 해보기