본문 바로가기

[React] 전역 상태의 필요성

[React] 전역 상태의 필요성

 

*  (프론트엔드에서의) 상태 관리의 개념과 필요성
*  로컬 상태와 전역 상태의 차이점 
*  전역 상태의 필요성 
*  상태 관리 라이브러리의 필요성 

 

 

상태 관리 


React는 상태 관리를 위한 라이브러리가 아니다.

  • 그러나  상태 관리의 주요 원칙을 배우고 이를 따라간다면,
  • 컴포넌트 간 서로 느슨하게 결합된(loose coupled), 구조적으로 아름다운 코드를 작성할 수 있다.

 

상태는 변하는 데이터이다.

특별히 UI, 프론트엔드 개발에서는 "동적으로 표현되는 데이터"이다.

 

여기에 쇼핑몰에서 흔하게 볼 수 있는 장바구니 화면이 있습니다. 여기에는 다양한 상태가 존재한다.

 

  • "장바구니에 담기"와 같은 버튼을 눌러, 해당 물품을 장바구니에 추가할 수 있다. 동적인 데이터이므로 이것은 상태이다.
  • 상단에 [일반구매/정기배송]중 현재 선택된 탭이 무엇인지 나타내는 상태가 있을 수 있다.
  • 상품 선택 여부에 따라 주문 금액이나 배송비가 달라진다. 선택 여부는 변할 수 있으므로 상태이다.
  • 상품 수량도 상태이다.

 

UI에서 상태 찾기

 

아래 그림은 상태에 따라 어떤 화면이 영향을 받는지 나타낸다.

 

 

이 화면을 컴포넌트로 분리해서 컴포넌트가 서로 어떤 상태를 공유하고, 주고받는지도 알아보았다. 

쇼핑몰 컴포넌트는 쇼핑몰 화면과 장바구니 화면 이렇게 크게 2개의 컴포넌트로 나뉜다.
그 뒤 장바구니 컴포넌트 안을 데이터 흐름을 바탕으로 구조화해보았다.

 

 

 

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


상태 관리 라이브러리의 역할

 

상태 관리 라이브러리는 어떤 문제를 해결해줄까?

  1. 전역 상태를 위한 저장소를 제공한다.
    • 상태의 출처를 파악하기 쉬워지기 때문에 코드의 유지보수가 좋아진다.
  2. 다음은, props drilling 문제를 해결한다.
    • 예를 들어, <A>라는 컴포넌트에 상태가 있고, <I>라는 컴포넌트가 해당 상태를 사용한다고 하면, 그 중간에 존재하는 <C>, <G> 등은 굳이 name이라는 상태가 필요하지 않음에도, 컴포넌트에 props를 만들어 자식 컴포넌트에 넘겨주어야 한다.
    • 이를 props drilling(프로퍼티 내려꽂기) 문제라고 부른다.
    • 전역 상태 저장소가 있고, 어디서든 해당 저장소에 접근할 수 있다면 이러한 문제는 해결될 것이다.

 

상태 관리 툴이 반드시 필요한 것은 아니다. 상태 관리 툴이 없어도 충분히 규모 있는 애플리케이션을 만들 수 있다. 

Redux의 개발자인 Dan Abramov도 'You Might Not Need Redux'라는 아티클을 통해, React 공식 문서의 "React로 사고하기"만 잘 따라와도 대부분의 문제를 해결할 수 있다고 언급한다. 

그러므로 장단점을 분명히 인지하고 상태 관리 툴을 쓰고,
               상태 관리의 기본기라고 볼 수 있는 "상태가 어디에 위치해야 하는지"를 먼저 익힌다.
728x90
⬆︎