2 minute read

React 상태관리

Achievement Goals

  • 상태 관리 라이브러리가 왜 필요한지 이해할 수 있다.
  • Redux (혹은 Flux Pattern)에서 사용하는 Action, Reducer 그리고 Store의 의미와 특징을 이해할 수 있다.
  • Redux의 3가지 원칙이 무엇이며, 주요 개념과 어떻게 연결되는지 이해할 수 있다.
  • Presentational 컴포넌트와 Container 컴포넌트의 개념을 이해할 수 있다.
  • Redux hooks(useSelector, useDispatch)를 사용해 store 를 업데이트할 수 있다.

Redux pattern

React와 같은 SPA를 개발할 때, 많은 컴포넌트의 페이지가 생성된다면, 컴포넌트 사이에 데이터 및 메소드의 접근이 매우 복잡해지는 경우가 발생할 수 있다. 이럴경우 특정 잡업을 하려고 여러 컴포넌트를 거쳐 props를 전달하게 되거나 컴포넌트는 props가 필요하지 않은데 자식 컴포넌트 때문에 필요한 props가 너무 많아지게 된다. 이러한 경우 최상위 컴포넌트에 상태관리 로직이 너무 많아 컴포넌트 코드 길이가 너무 길어지고 가독성도 떨어지게 된다.

**리덕스는 이러한 불필요한 상태 관리 로직을 컴포넌트 밖에서 처리하는 방식으로 문제를 해결해준다. **


리덕스는 스토어(store)라는 객체 내부에 상태를 담아서 사용한다. 스토어에서 모든 상태관리가 일어나게 된다. 상태에 따라 어떤 변화를 일으켜야 할 때는 액션(action)이란 객체를 스토어에 전달하고 스토어는 액션을 참조해 변화를 일으킨다. 액션을 전달하는 과정은 디스패치(dispatch)라고 한다. 스토어가 액션을 받으면 리듀서(Reducer)가 전달받은 액션을 기반으로 상태를 어떻게 변경시켜야 할 지 정한다. 액션을 처리하면 새 상태를 스토어에 저장한다.


  • 스토어 : 상태 보관소. state와 reducer로 구성된다.
  • 액션 : 상태 변화를 일으킬 때 참조하는 객체
  • 디스패치 : 액션을 스토어에 전달하기 위한 인터페이스
  • 리듀서 상태를 변화시키는 로직이 있는 함수

리덕스의 3가지 원칙

1. 애플리케이션의 모든 상태(state)는 하나의 저장소(store) 안에 하나의 객체 트리 구조로 저장된다.

하나의 저장소(store)가 존재하며, 이 저장소(store)에는 애플리케이션의 모든 상태들이 객체 트리 구조로 저장되어 있다. -> 서버로부터 가져온 상태는 직렬화(serialized)되거나, 수화되어(hydrated) 전달되며 클라이언트에서 추가적인 코딩 없이도 사용할 수 있다. 하나의 상태 트리만을 가지고 있기 때문에 디버깅에도 용이하다.

직렬화(serialize)란? 직렬화 예시, localstorage는 값으로 string을 가질 수 있지만 object는 가질 수 없다. 이때, json.stringify를 통해서 object를 string화한다. 이것이 직렬화다. 다시 꺼내쓸 때는 json.parse를 하여 다시 string을 object화 하는데, 이것이 역직렬화다. 이때, 직렬화 전 object와 역직렬화된 object는 같아야 한다. -> redux에서 function,promise등과 같은 non-serializable type을 저장하면, redux-devtools에서 표시가 안되고, 또 콘솔에서 경고 메세지를 던진다. redux에서는 store의 일관성 유지, 복원 기능, 시간여행 디버깅 등이 방해받을 수 있기에 non-serializable type을 저장하는 걸 권하지 않는다고 한다.

2. 상태(state)는 읽기 전용(read-only)이다.

상태(state)는 읽기 전용이다. 상태를 변화시키는 유일한 방법은 무슨 일이 벌어지는 지를 묘사하는 액션 객체를 전달하는 방법뿐이다. -> 이를 통해서 뷰(view)나 네트워크 콜백에서 상태를 직접 바꾸지 못한다는 것을 보장 할 수 있다. 모든 상태 변화는 중앙에서 관리되며 모든 액션은 엄격한 순서에 의해 하나하나 실행되기 때문에 신경써 관리해야할 경쟁 상태는 없다.

3. 변화는 순수 함수로 작성되어야 한다.

액션에 의해 상태 트리가 어떻게 변화하는 지를 지정하기 위해 프로그래머는 순수 리듀서를 작성해야 한다. -> 리듀서는 그저 이전 상태와 액션을 받아 다음 상태를 반환하는 순수함수이다. 이전 상태를 변경하는 것이 아니라, 새로운 상태 객체를 생성해서 반환해야한다는 사실을 기억해야 한다.

순수 함수란? 동일한 인자가 주어졌을 때 항상 동일한 결과를 반환해야 하며, 외부의 상태를 변경하지 않는 함수 -> 즉, 함수 내 변수 외에 외부의 값을 참조, 의존하거나 변경하지 않는 함수

Redux-thunk

리덕스를 사용할때 비동기 처리를 할 때는 redux-thunk 미들웨어를 사용한다. thunk는 특정 작업을 나중에 할 수 있도록 미루려고 함수 형태로 감싼 것을 말한다.

const x = 1 + 2; // 이 코드를 실행하면 1 + 2 연산을 바로 실행한다.

const foo = () => 1 + 2; // 이렇게 하면 1 + 2 연산을 코드가 실행될 때 바로 하지 않고 foo()함수가 호출될 때 한다.

자세한 내용은 공식문서를 참고해 공부하자.