목록으로
이번 편에서는 전 편에서 다룬 useState() 함수를 조금 더 살펴봅니다.
useState란?
React의 useState() 함수는 함수 컴포넌트에서 지역 상태(local state)를 생성하고 관리하기 위한 리액트 훅(Hook)입니다. 컴포넌트가 다시 렌더링되어도 상태를 기억하고 유지할 수 있게 해주는 핵심 기능입니다.
초반에 우리가 만든 Subscription 컴포넌트 코드를 꺼내 보겠습니다.
두 번째 줄에 useState() 함수가 보이죠? 함수 컴포넌트는 JavaScript 언어 관점에선 함수입니다. 함수는 호출하면 내부 변수들이 생성되지만 함수가 종료되면 모두 사라집니다. 즉 상태가 유지되지 않지요. useState() 함수는 함수 내부라는 지역(local)에 상태를 생성하고 관리하는 기능을 제공합니다.
컴포넌트와 지역성
React는 컴포넌트 기반 모델을 채택하고 있습니다. 컴포넌트는 지역적으로 상태를 관리하는 게 중요한데, 그래야 컴포넌트가 격리되어 재사용하기 용이하기 때문입니다. 컴포넌트에서 상태란 이전 편에서 버튼을 예시로 다뤘지요. 이러한 지역성은 다음과 같은 이점을 제공합니다.
-
컴포넌트 간의 독립성 보장
-
코드의 재사용성 향상
-
테스트와 디버깅 용이성
-
상태 관리의 단순화
이런 컴포넌트가 마치 함수같지 않나요? 컴포넌트는 마치 순수(pure) 함수처럼 동작합니다. 순수 함수가 안 되더라도 적어도 멱등성을 갖습니다. 상태가 변하지 않는 한 몇 번을 호출해도 결과가 동일하지요.
상태 변경하기
useState() 함수를 호출하면 두 개 객체를 배열에 담아 반환합니다. 이 함수의 인자는 상태값의 초기값을 설정합니다. useState() 함수가 반환하는 배열의 첫 번째 객체는 상태 객체로 값을 갖습니다. 두 번째 객체는 상태 값 변경 함수입니다. 첫 번째 객체를 직접 변경해서는 안 됩니다.
이는 React의 단방향 데이터 흐름을 유지하고, 리렌더링이 오작동하는 것을 방지합니다.
베일아웃(Bailout)
베일아웃은 React의 성능 최적화 기능 중 하나로, 새로운 상태가 이전 상태와 동일할 경우 불필요한 리렌더링을 방지합니다.
참조 타입 다루기
베일아웃은 간혹 입문자를 혼란에 빠뜨리는데, 배열이나 객체처럼 참조 타입을 상태 값으로 다룰 때 혼란에 빠뜨리곤 합니다.
JavaScript는 배열과 객체를 값으로 다루지 않고 참조해서 다룹니다.
이 이미지는 참조로 대상을 전달해 다루는 것과 값으로써 대상을 전달해 다루는 것을 표현하는 유명한 이미지입니다. 왼쪽은 참조로 전달하는 것으로, 컵이라는 객체를 직접 전달하는 게 아니라 컵에 연결된 개체를 전달한 것입니다. 따라서 참조 대상인 컵에 커피를 따르자 원본 컵에도 커피가 차오릅니다. 둘은 실질적으로 동일한 객체이기 때문이지요. 하지만 값으로 전달하는 오른쪽 이미지는 컵이 그 자체로 전달됐으므로(복사) 전달된 컵에 커피를 따라도 원본 컵엔 아무런 일도 벌어지지 않습니다. 컵 두 개가 된 것이니까요.
Python 등 몇 몇 언어와 마찬가지로 JavaScript도 배열이나 객체 등 일부 자료형(타입)을 참조 타입(자료형)으로 다룹니다.
이 코드에서 member 객체는 컨테이너로써 객체이며 내부 내용인 member.name을 수정해도 컨테이너 그 자체인 member 객체는 동일하게 유지됩니다. 컨테이너 내용물만 바뀐 것이지요.
그래서 이와 같이 {과 } 표현식으로 새 객체를 생성해야 비로소 member와 member2가 서로 다른 객체가 됩니다. 또는,
이와 같이 전개 구문(Spread syntax, Spread operator)을 사용해 보다 간편하게 새 객체를 만들기도 합니다.
함수로 상태 변경하기
여태까지 객체 변경 함수(예 : setEmail())로 상태값을 변경할 때 변경할 새 값을 인자로 전달했습니다.
상태 값을 변경하는 또 다른 방법은 함수를 인자로 전달하는 것입니다.
이전 편에서 다룬 리액트의 상태 관리 동작의 특성으로 기인하는 몇 몇 상황에서 이러한 방법이 필요합니다.
최신 상태 값 보장
리액트는 내부적으로 비동기로 렌더링과 상태 관리를 합니다. 따라서 setCount(count + 10)을 호출하는 시점에 count 상태값이 몇 인지 확언하기 어렵습니다. 1에다 1을 더해 2인 상태에서 count + 10을 실행해 12가 될 것이라 예상하지만 11이 되는 경우도 발생할 수 있습니다.
그에 반해 함수로 상태 값을 변경하면 리액트는 count의 값이 최신 상태 값이라는 걸 보장합니다.
연속된 상태 갱신 처리
이 역시 비동기 처리와 관련된 경우입니다.
이 코드의 경우 첫 번째 갱신이 이뤄지지 않은 count 상태 값을 사용하게 됩니다. count 초기 값이 1이라면, 첫 번째 상태 값 변경으로 count는 2, 두 번째 상태 값 변경으로 count는 3이 되길 기대하지만, 첫 번째 상태값이 반영되기 전에 두 번째 상태 값 변경을 실행하는 경우 최종 count는 3이 아닌 2가 되는 거지요.
푸딩캠프 뉴스레터를 구독하면 학습과 성장, 기술에 관해 요약된 컨텐츠를 매주 편하게 받아보실 수 있습니다.
목차