* (프론트엔드에서의) 상태 관리의 개념과 필요성
* 로컬 상태와 전역 상태의 차이점
* 전역 상태의 필요성
* 상태 관리 라이브러리의 필요성
상태 관리
React는 상태 관리를 위한 라이브러리가 아니다.
- 그러나 상태 관리의 주요 원칙을 배우고 이를 따라간다면,
- 컴포넌트 간 서로 느슨하게 결합된(loose coupled), 구조적으로 아름다운 코드를 작성할 수 있다.
상태는 변하는 데이터이다.
특별히 UI, 프론트엔드 개발에서는 "동적으로 표현되는 데이터"이다.
여기에 쇼핑몰에서 흔하게 볼 수 있는 장바구니 화면이 있습니다. 여기에는 다양한 상태가 존재한다.
- "장바구니에 담기"와 같은 버튼을 눌러, 해당 물품을 장바구니에 추가할 수 있다. 동적인 데이터이므로 이것은 상태이다.
- 상단에 [일반구매/정기배송]중 현재 선택된 탭이 무엇인지 나타내는 상태가 있을 수 있다.
- 상품 선택 여부에 따라 주문 금액이나 배송비가 달라진다. 선택 여부는 변할 수 있으므로 상태이다.
- 상품 수량도 상태이다.
UI에서 상태 찾기
아래 그림은 상태에 따라 어떤 화면이 영향을 받는지 나타낸다.
이 화면을 컴포넌트로 분리해서 컴포넌트가 서로 어떤 상태를 공유하고, 주고받는지도 알아보았다.
Side Effect
상태를 다룰 때에 Side Effect는 주요 고려 대상이다.
[Side Effect의 정의]
함수(또는 컴포넌트)의 입력 외에도 함수의 결과에 영향을 미치는 요인
: 대표적으로 네트워크 요청, API 호출이 Side Effect
- React의 주요 개발 원칙 중 하나는 UI를 페이지 단위가 아닌 컴포넌트 단위로 보는 것이다.
만일 아래와 같이 <CartItem>이라는 컴포넌트를 만든다면, fetch와 같은 API 요청이 없이도 이 컴포넌트는 작동되어야 한다. - (즉, Side Effect를 최대한 배제하고 컴포넌트를 만든다.)
- 어떤 데이터가 들어오는지 상관하지 않고, 설사 데이터가 가짜 데이터라 할지라도 컴포넌트는 표현(presentation) 그 자체에 집중한다.
하지만,
앱을 만들다 보면 분명 API 호출도 해야 하고, side effect는 불가피하게 생기기 마련이다.
이러한 side effect에 의존적인 상태도 있을 수 있다.
- 예를 들어 "로딩 중"을 나타낼 것인지 아닌지 여부는 데이터 전송 여부에 따라 달려 있다.
- 장바구니 데이터가 서버에 있다면 네트워크 요청(fetch 등) 때문에 오래 걸릴 수 있다.
- 이때 로딩이 뜬다면 데이터 로딩 여부(isLoading)라는 상태가 true이며 이 상태는 side effect에 의존적이다.
로컬 / 전역 상태
(상태를 구분하는 데에는 절대적인 기준이나 법칙이 있는 것은 아니다.)
- 로컬 상태 : 특정 컴포넌트 안에서만 관리되는 상태
- 보통 컴포넌트 내에서만 영향을 끼치는 상태는 로컬 상태이다.
- 다른 컴포넌트와 데이터를 공유하지 않는 폼(form) 데이터는 대부분 로컬 상태이다.
- (input box, select box, radio button 등과 같이 입력값을 받는 경우)
- 위의 예시 <CartItem> 컴포넌트의 경우, '선택한 수량'이 로컬 상태이다.
- 원래 가격에 상태를 곱해 컴포넌트 내에 표시되는 주문 금액을 업데이트하면 된다.
- 전역 상태 : 프로덕트 전체 혹은 여러 가지 컴포넌트가 동시에 관리하는 상태
- 전역 상태는 다른 컴포넌트와 상태를 공유하고 영향을 끼치는 상태이다.
- 아래의 그림에서 장바구니에 담긴 물품의 경우,
- 상품 선택 여부에 따라 총 주문 금액을 업데이트해야 한다.
- 장바구니에 담긴 물품은 그 갯수 등을 다른 컴포넌트에 전달해 주어야 한다.
아까 언급한 데이터 로딩 여부(로딩 중) 상태 역시, 앱 전반에 영향을 미친다. JavaScript에서 전역 변수를 남용하는 것은 좋지 않다고 배웠지만, 경우에 따라 전역 상태가 필요하다.
서로 다른 컴포넌트가 사용하는 상태의 종류가 다르면, 꼭 전역 상태일 필요는 없다. 출처(source)가 달라도 된다.
그러나, 서로 다른 컴포넌트가 동일한 상태를 다룬다면, 이 출처는 오직 한 곳이어야 한다.
- 만일 사본이 있을 경우, 두 데이터는 서로 동기화(sync)하는 과정이 필요한데, 이는 문제를 어렵게 만든다.
- 한 곳에서만 상태를 저장하고 접근한다.
- 여기서 '하나의 출처'는 다른 말로 이야기하면 '전역 공간'이라고 볼 수 있다.
데이터 무결성
- 데이터 무결성을 위해, 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 오도록 한다.
- Single source of truth(신뢰할 수 있는 단일 출처) 원칙은 프론트엔드 뿐만 아니라 다양한 곳에서 언급되는 원칙dl다.
- 데이터가 존재하고, 그 데이터를 보여줘야 하는 프론트엔드에서는 철저하게 우리가 의도한 대로 예외 상황 없이 데이터를 잘 보여주어야 할 것이다.
- 즉, 우리가 보여주고자 하는 데이터가 있다면 그 데이터가 어떤 경우에도 UI 상에 잘못 전달되는 일이 없게 만드는 것이 중요하다.
전역 상태 관리 Case study
전역으로 상태를 관리해야 하는 경우를 살펴보면 다음과 같다.
1. 라이트 / 다크 모드 테마
모든 페이지, 모든 컴포넌트에 다크 모드 혹은 라이트 모드가 적용이 되어야 하기 때문에 이러한 테마 설정을 전역으로 관리할 수 있다.
2. 국제화(Globalization) 설정
사용자가 사용하는 브라우저나, 운영체제가 특정 언어를 사용하고 있음을 알아내서, UI에 필요한 텍스트 리소스를 따로 저장한 후, 전역 상태로 관리하기도 한다.
이 기능의 경우에도 모든 컴포넌트에서 사용자 언어로 표현이 되어야 하기 때문에 전역에서 상태 관리가 필요하다.
3. Undo / Redo 기능
포토샵이나 일러스트레이터에는 히스토리 기능과 Undo/Redo를 지원한다. 화면에 표시되는 모든 내용을 전부 상태 객체로 만들어서 저장해버린다면, 원하는 특정 상태를 바탕으로 컴포넌트를 표현할 수도 있다. 이것이 Undo/Redo, 히스토리 기능의 작동 원리이다.
상태 관리 라이브러리
상태 관리를 도와주는 각종 툴이 있다. 이 세 가지는 현업에서 쓰일 가능성이 매우 많다.
- React Context
- Redux
- Mobx
상태 관리 라이브러리의 역할
상태 관리 라이브러리는 어떤 문제를 해결해줄까?
- 전역 상태를 위한 저장소를 제공한다.
- 상태의 출처를 파악하기 쉬워지기 때문에 코드의 유지보수가 좋아진다.
- 다음은, props drilling 문제를 해결한다.
- 예를 들어, <A>라는 컴포넌트에 상태가 있고, <I>라는 컴포넌트가 해당 상태를 사용한다고 하면, 그 중간에 존재하는 <C>, <G> 등은 굳이 name이라는 상태가 필요하지 않음에도, 컴포넌트에 props를 만들어 자식 컴포넌트에 넘겨주어야 한다.
- 이를 props drilling(프로퍼티 내려꽂기) 문제라고 부른다.
- 전역 상태 저장소가 있고, 어디서든 해당 저장소에 접근할 수 있다면 이러한 문제는 해결될 것이다.
상태 관리 툴이 반드시 필요한 것은 아니다. 상태 관리 툴이 없어도 충분히 규모 있는 애플리케이션을 만들 수 있다.
Redux의 개발자인 Dan Abramov도 'You Might Not Need Redux'라는 아티클을 통해, React 공식 문서의 "React로 사고하기"만 잘 따라와도 대부분의 문제를 해결할 수 있다고 언급한다.
그러므로 장단점을 분명히 인지하고 상태 관리 툴을 쓰고,
상태 관리의 기본기라고 볼 수 있는 "상태가 어디에 위치해야 하는지"를 먼저 익힌다.
'FE > React' 카테고리의 다른 글
쇼핑몰 애플리케이션에서 Hooks를 이용한 상태 관리 (0) | 2023.04.24 |
---|---|
Props Drilling이란? (0) | 2023.04.21 |
Styled Components로 ClickToEdit 만들기 (0) | 2023.04.20 |
Styled Components로 Tag 만들기 (0) | 2023.04.20 |
Styled Components로 Tab 만들기 (0) | 2023.04.20 |