State를 보존하고 초기화하기
💡이번 챕터에서 알아가는 내용
React에서 상태가 언제 유지되고, 언제 초기화되는지 알 수 있습니다.
컴포넌트가 업데이트/재랜더링될 때 상태를 유지하거나 초기화하는 경우에 대해 알 수 있습니다.
State는 렌더트리의 위치를 통해 컴포넌트와 연결합니다.
React는 컴포넌트가 UI 트리의 어떤 위치에 있는지 파악하고, 위치를 기반으로 각 state를 연결합니다.
다음 React tree에서 Counter 컴포넌트 2개는 서로 다른 컴포넌트 2개입니다. 또한 분리된 state를 가지고 있습니다. 그래서 서로의 state에 영향을 주지 않습니다.
한 Counter 컴포넌트를 삭제하고 다시 추가했을 때, 해당 컴포넌트의 state가 다시 초기화되는 것을 볼 수 있습니다. React는 컴포넌트를 제거할 때 state도 같이 제거합니다.
즉, React는 같은 컴포넌트가 같은 자리에서 리렌더링되는 한 state를 유지합니다.
같은 자리의 같은 컴포넌트는 state를 유지합니다.
위에서 설명한 것처럼, 같은 자리의 같은 컴포넌트는 제거되지 않는 한 state를 유지합니다. 이때 같은 자리는 JSX 코드 상에서가 아닌 UI 트리에서의 자리를 의미합니다.
다음처럼 조건부 렌더링으로 코드를 작성할 때도, 실제 UI 트리에서의 Counter 컴포넌트의 위치는 변하지 않습니다. 따라서 상위 컴포넌트에 의해 리랜더링될 때도 Counter 컴포넌트의 state는 유지됩니다.
같은 위치의 다른 컴포넌트는 state를 초기화합니다.
같은 자리의 한 컴포넌트를 다른 컴포넌트로 바꾼다면, 기존 컴포넌트의 state는 초기화됩니다.
때문에 리렌더링할 때 state를 유지하고 싶다면 완전히 같은 트리 구조를 갖고 있어야 합니다.
또한 같은 위치에서 같은 컴포넌트가 새로 정의될 때(초기화 시)에도 state는 초기화됩니다. 그래서 컴포넌트는 중첩해서 사용하는 것이 아닌, 최상위에서 정의해야 합니다.
같은 위치의 같은 컴포넌트에서 state를 초기화하고 싶을 때
같은 위치의 컴포넌트를 사용하더라도, 필요에 따라 state를 초기화하고 싶을 수 있습니다. 이를 위한 2가지 방법이 있습니다.
다른 위치에 컴포넌트를 렌더링하기
각 컴포넌트에
key로 명시적인 식별자를 제공하기
1. 다른 위치에 컴포넌트를 렌더링하기
아래 코드처럼 삼항 연산자(조건부 연산자)를 통해 컴포넌트를 렌더링하면, 두 Counter는 같은 위치에 나타나기 때문에 state가 그대로 유지됩니다.
만약 두 Counter를 독립적으로 사용하고 싶다면 논리 연산자를 사용해서 다른 위치에 렌더링하도록 바꿉니다.
❓ 왜 조건부 연산자(?:)는 같은 컴포넌트로 인식되고, 논리 연산자(&&)는 새로운 컴포넌트로 인식될까?
JSX에서
{cond ? <A /> : <B />}는 “cond이면<A />를 렌더링하고, 그렇지 않으면<B />를 렌더링합니다.” 를 의미합니다.JSX에서
{cond && <A />}는 “cond이면,<A />를 렌더링하되, 그렇지 않으면 아무것도 렌더링하지 않습니다.” 를 의미합니다.
같은 위치에서 같은 컴포넌트가 존재하면 기존 상태가 유지됩니다.
컴포넌트가 없어졌다가 다시 생성되면 새로운 컴포넌트로 간주하여 상태를 초기화합니다.
조건부 연산자의 경우, 동일한 위치에서 Counter 컴포넌트를 유지하고 속성만 변경합니다.
논리 연산자의 경우, 기존 컴포넌트가 없어졌다가 새로운 Counter 컴포넌트가 추가됩니다.
2. key를 이용해 state를 초기화하기
React는 컴포넌트를 구별하기 위해 기본적으로 부모 컴포넌트 안에서의 순서를 이용하지만, key 를 이용한다면 컴포넌트를 특정하여 쉽게 구별할 수 있습니다.
위와 같이 key를 명시한다면 두 컴포넌트가 자리가 같아도 React에서 다른 컴포넌트라고 인식하게 됩니다. 따라서 state를 초기화할 수 있습니다.
➕key를 이용해 폼을 초기화하기
key를 통해 같은 위치의 컴포넌트들을 다른 컴포넌트로 인식하게 하여, state를 초기화할 수 있다는 것을 알았습니다. 이를 폼을 초기화할 때 유용하게 사용할 수 있습니다.
form 마크업을 가지고 있는 Chat 컴포넌트에서 key를 부여하게 된다면, 부모 컴포넌트의 state가 바뀔 때마다 key값이 바뀌어 새로운 컴포넌트로 인식됩니다. 따라서 기존 DOM 엘리멘트를 다시 사용(리렌더링)하지 않고, 새로운 자식 컴포넌트가 정의되어 그에 포함된 state도 초기화됩니다.
만약 이전의 Chat 컴포넌트의 state를 복구시키고 싶다면, 다음과 같은 방법을 사용할 수 있습니다.
모든 채팅을 렌더링하되, CSS를 이용하여 현재 채팅만 보이지 않게 하기
state를 상위로 올리고, 각 입력값들을 부모 컴포넌트에서 관리하기 ⇒ 가장 일반적인 방법
다른 저장소에 값을 저장해두기 ex) localStorage, SessionStorage
Last updated