State: 컴포넌트의 기억

State: 컴포넌트의 기억

컴포넌트는 보통 어떤 값을 '기억'해야 해요 — 입력 중인 텍스트, 현재 보고 있는 이미지, 장바구니에 담긴 목록까지. 그런데 함수는 실행이 끝나면 지역 변수가 사라지니까, 렌더링 사이에 값을 보관하려면 남들과 구분되는 저장소가 필요해요. React에서는 이렇게 컴포넌트 고유의 기억 공간을 state라고 불러요.

출처: React 공식 문서 — State: A Component's Memory

일반 변수로는 왜 부족할까요

props처럼 이미 받은 값은 그대로 보여주면 되지만, 사용자 입력에 따라 바뀌는 값은 얘기가 달라요. 일반 지역 변수는 렌더링이 끝나면 휘발되기 때문에, 렌더링 사이에 값을 보존하려면 두 가지가 필요해요.

  1. 렌더링 사이 데이터를 품고 있는 state 변수
  2. 값을 바꾸면서 React에게 다시 그리라고 알려주는 setter 함수

useState가 이 두 개를 배열로 돌려준답니다.

첫 번째 Hook, useState

useState는 React의 훅 중 하나예요. 훅은 함수지만, 컴포넌트의 '필요 사항을 선언'한다고 보는 게 이해에 도움이 돼요. 파일 위에서 모듈을 import 하듯, 컴포넌트 함수의 최상단에서 기능을 '사용'한다고 생각하면 돼요.

const [index, setIndex] = useState(0);

useState에 넘기는 유일한 인자는 state 변수의 초깃값이에요. 위 코드는 초깃값 0을 넣어 [0, setIndex]을 받는 셈이죠. 값이 바뀌는 흐름을 따라가 보면 이래요.

  1. 컴포넌트가 처음 렌더링될 때, useState(0)index0인 배열을 돌려줘요. React는 최신 값이 0임을 기억해요.
  2. 사용자가 버튼을 눌러 setIndex(1)을 호출하면, React는 index1로 기억하고 다시 렌더링을 예약해요.
  3. 두 번째 렌더링에서도 코드는 여전히 useState(0)이지만, React가 값을 바꿔놨으므로 [1, setIndex]을 돌려줘요. 초깃값은 첫 렌더링에서만 의미가 있는 거예요.

state는 여러 개 둘 수 있어요

컴포넌트 하나에 useState를 여러 번 부르면 여러 state 변수를 가질 수 있어요. 다만 form처럼 필드가 많은 경우엔 필드마다 변수를 두기보다 객체 하나를 state로 두는 편이 다루기 쉬울 때가 많아요. React는 컴포넌트마다 state 쌍 배열을 들고 있고, useState를 호출할 때마다 다음 순서의 state를 돌려줘요. 그래서 훅의 순서가 바뀌면 안 되는 거예요.

state는 격리되고 비공개예요

state는 특정 함수 호출이나 코드 위치가 아니라, 화면에 있는 컴포넌트 인스턴스에 묶인 값이에요. 같은 컴포넌트를 두 번 렌더링하면 두 인스턴스는 완전히 독립된 state를 가져서, 하나를 바꿔도 다른 쪽은 영향받지 않아요. 또 props와 달리 state는 선언한 컴포넌트만 접근할 수 있고 부모가 건드릴 수 없어요.

만약 두 화면의 state를 동기화하고 싶다면, 각 자식이 state를 갖게 하는 대신 가장 가까운 공통 부모로 state를 올려서 내려주는 게 React의 정석이에요. 그리고 렌더링 사이에 보관할 필요가 없는 값은 굳이 state로 만들지 않아요 — 이벤트 핸들러 안에서만 쓰이는 값은 일반 변수로 충분해요.

더 알아보기