State 관리하기
- Published on
- 리액트 애플리케이션에서 상태 관리에 대한 핵심 원칙과 기법을 익히고, UI 변경과 상태 업데이트를 효과적으로 다루는 방법을 배웁니다.
애플리케이션이 커지면서 상태를 어떻게 구성하고 구성 요소 간에 데이터가 어떻게 흐르는지에 대해 의도적으로 고려하는 것이 도움이 됩니다. 중복된 상태는 버그의 일반적인 원인입니다. 이 장에서는 상태를 잘 구조화하는 방법, 상태 업데이트 로직을 유지보수하기 좋게 유지하는 방법, 그리고 먼 컴포넌트 간에 상태를 공유하는 방법을 배우게 됩니다.
이 장에서 배우는 내용
- UI 변경을 상태 변경으로 생각하는 방법
- 상태를 잘 구성하는 방법
- 상태를 "끌어올려" 컴포넌트 간에 공유하는 방법
- 상태의 보존 또는 초기화 여부를 제어하는 방법
- 복잡한 상태 로직을 함수로 통합하는 방법
- "속성 던지기" 없이 정보를 전달하는 방법
- 앱이 성장함에 따라 상태 관리의 확장
상태 변경으로 UI 반응하기
리액트에서는 코드에서 직접 UI를 수정하지 않습니다. 예를 들어, "버튼 비활성화", "버튼 활성화", "성공 메시지 표시"와 같은 명령을 작성하지 않습니다. 대신 컴포넌트의 다양한 시각적 상태에 대해 보고자 하는 UI를 설명하고, 사용자 입력에 대한 상태 변경을 트리거합니다. 이는 디자이너가 UI를 생각하는 방식과 유사합니다.
리액트를 사용하여 작성된 퀴즈 양식 예제를 살펴보세요. 상태 변수인 status
를 사용하여 제출 버튼을 활성화 또는 비활성화하고 성공 메시지를 표시할지를 결정합니다.
상태 구조 선택하기
상태를 잘 구성하는 것은 수정 및 디버깅하기 쉬운 컴포넌트와 버그의 지속적인 원인이 되는 컴포넌트 사이의 차이를 만들 수 있습니다. 가장 중요한 원칙은 상태에 중복된 정보가 포함되지 않아야 한다는 것입니다. 불필요한 상태가 있는 경우 업데이트를 잊어버리고 버그를 도입하기 쉽습니다!
예를 들어, 이 양식에는 fullName
이라는 중복된 상태 변수가 있습니다. 이를 제거하고 컴포넌트가 렌더링되는 동안 fullName
을 계산하여 코드를 단순화할 수 있습니다. 이 작은 변경은 보통 리액트 앱의 많은 버그를 수정하는 데 도움이 됩니다.
컴포넌트 간에 상태 공유하기
때로는 두 컴포넌트의 상태가 항상 함께 변경되길 원할 수 있습니다. 이를 위해 두 컴포넌트에서 상태를 제거하고, 가장 가까운 공통 상위 컴포넌트로 이동한 다음, 해당 상태를 props를 통해 자식 컴포넌트에 전달합니다. 이를 "상태 끌어올리기"라고 하며, 리액트 코드를 작성할 때 가장 일반적으로 수행하는 작업 중 하나입니다.
이 예에서는 한 번에 하나의 패널만 활성화되어야 합니다. 이를 위해 각 개별 패널 내에서 active
상태를 유지하는 대신 상위 컴포넌트에서 상태를 유지하고 자식 컴포넌트에 대한 props를 지정합니다.
상태 보존과 재설정
컴포넌트를 다시 렌더링할 때, 리액트는 이전에 렌더링된 컴포넌트 트리와 "일치하는" 부분을 유지(업데이트)하고, 폐기하거나 처음부터 다시 생성할 부분을 결정해야 합니다. 대부분의 경우, 리액트의 자동 동작은 충분히 잘 작동합니다. 기본적으로 리액트는 이전에 렌더링된 컴포넌트 트리와 "일치하는" 트리 부분을 보존합니다.
하지만 때로는 이게 원하는 동작이 아닐 수 있습니다. 이 채팅 앱에서 메시지를 입력하고 수신자를 전환하면 입력이 재설정되지 않습니다. 이는 사용자가 실수로 잘못된 수신자에게 메시지를 전송하는 원인이 될 수 있습니다.
리액트를 사용하면 기본 동작을 재정의하고 컴포넌트가 상태를 재설정하도록 강제할 수 있습니다. <Chat key={email} />
와 같이 다른 키를 전달하여 컴포넌트에 새로운 키를 전달함으로써 이를 수행할 수 있습니다. 이렇게 하면 리액트에게 수신자가 다르다면 새로운 Chat 컴포넌트로 간주되어 새 데이터(및 입력과 같은 UI)로 처음부터 다시 생성되어야 함을 알립니다. 이제 수신자 간 전환을 수행하면 입력 필드가 재설정됩니다. 비록 동일한 컴포넌트를 렌더링하지만 그렇습니다.
상태 로직을 리듀서로 추출하기
많은 이벤트 핸들러에 걸쳐 많은 상태 업데이트가 분산되는 컴포넌트는 복잡해질 수 있습니다. 이러한 경우에는 컴포넌트 외부에 모든 상태 업데이트 로직을 단일 함수인 "리듀서"로 통합할 수 있습니다. 이벤트 핸들러는 사용자 "액션"만을 지정하기 때문에 간결해집니다. 파일의 맨 아래에서 리듀서 함수는 각 액션에 대한 상태 업데이트 방식을 지정합니다!
컨텍스트를 사용하여 데이터 깊게 전달하기
일반적으로 부모 컴포넌트에서 자식 컴포넌트로 정보를 전달할 때는 props를 사용합니다. 그러나 많은 컴포넌트를 통해 일부 prop을 전달해야 하는 경우나 많은 컴포넌트가 동일한 정보가 필요한 경우 props 전달은 불편할 수 있습니다. 컨텍스트를 사용하면 부모 컴포넌트가 하위 트리의 모든 컴포넌트에서 사용할 수 있도록 일부 정보를 명시적으로 전달하지 않고도 해당 정보를 사용할 수 있습니다.
여기에서 Heading
컴포넌트는 가장 가까운 Section
으로부터 수준을 "질문"하여 제목 수준을 결정합니다. 각 Section
은 부모 Section
에게 질문한 다음 하나를 추가하여 자체 수준을 추적합니다. 각 Section
은 명시적으로 props를 전달하지 않고도 하위 모든 컴포넌트에 정보를 제공합니다.
리듀서와 컨텍스트를 사용하여 확장하기
리듀서를 사용하여 컴포넌트의 상태 업데이트 로직을 통합할 수 있습니다. 컨텍스트를 사용하면 다른 컴포넌트로 깊이 있는 정보를 전달할 수 있습니다. 리듀서와 컨텍스트를 결합하여 복잡한 화면의 상태를 관리할 수 있습니다.
이 접근 방식을 사용하면 복잡한 상태를 가진 상위 컴포넌트가 리듀서로 상태를 관리합니다. 트리의 깊은 곳에 있는 다른 컴포넌트는 컨텍스트를 통해 해당 상태를 읽을 수 있습니다. 또한 상태를 업데이트하기 위해 액션을 디스패치할 수도 있습니다.
다음에 알아보기
사용자 입력 State 처리
리액트를 사용하여 선언적 UI 프로그래밍을 구현하는 방법과 UI 상태를 관리하는 전략에 대한 설명을 제공합니다.
State 구조 선택
리액트 애플리케이션에서 상태를 구조화하고 관리하는데 유용한 원칙과 팁을 소개합니다.
컴포넌트간 State 공유
리액트 애플리케이션에서 컴포넌트 간 상태 공유를 위해 상태를 공통 부모 컴포넌트로 "위로 올리는" 방법을 다룹니다.
State 보존과 재설정
리액트에서 컴포넌트 간 상태를 보존하고 리셋하는 방법에 대한 설명을 제공합니다.
Reducer: State 로직 추출
useState에서 useReducer로 상태 관리 로직을 개선하는 방법과, 리듀서 작성 시 주의할 점에 대해 설명합니다.
Context: 데이터 깊이 전달
리액트 컨텍스트를 사용하여 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 방법에 대한 내용을 다루고 있습니다.
Reducer와 Context 활용
듀서와 컨텍스트를 결합하여 리액트 앱에서 상태를 관리하고 컴포넌트 간 데이터 공유를 효율적으로 처리하는 방법을 학습합니다.