본문 바로가기

React/이론

[React] Redux

들어가며.

이 글은 최대한 Redux의 공식 홈페이지를 토대로 Redux를 정리 및 이해하려고 한다. 

 

동기. 

자바스크립트 싱글 페이지 애플리케이션이 갖추어할 요건이 점점 더 복잡해지고있는 만큼,
어느 때보다도 많은 상태를 자바스크립트 코드로 관리할 필요가 생겨났습니다

상태에는 서버 응답, 캐시 데이터, 지역적으로 생성해서 사용하고 있지만 아직 서버에 저장되지 않은
데이터를 의미

실제로 프론트엔드를 개발하다보면 생각보다 많은 곳에서 State를 사용해야한다.

예를들어, 작은 모달창을 화면에 나오게 하기 위해서도 isModal 과 같은 상태를 만들어준다. 

 

항상 변하는 상태를 관리하기란 어렵습니다...
상태를 언제, 왜, 어떻게 업데이트할지 제어할 수 없는 지경에 이르고 맙니다.

그렇다. 부모 컴포넌트에서 자식 컴포넌트에게 상태의 변경 권한을 주기도 하고,  

또 자식의 자식 컴포넌트가 그 권한이 필요해서 자식 컴포넌트는 필요 없는 권한을 

가지고 있어야 하기도 한다. 

 

점점 많아지는 상태를 쉽게 관리하기 위해서 Redux라는 라이브러리가 나오게 되었다. 

 

정말 맞는 말인 것 같다. 

우리가 프론트엔드 개발을 할 때, Redux를 사용하는 환경 (혹은 어떤 상태관리 시스템)과 

사용하지 않는 환경의 개발의 편리함(?) 차이는 굳이 말할 필요가 없다. 

( 그것이 상태 관리 라이브러리가 꼭 필요 없는 환경일지라도... )

 

Flux, CQRS, Event Sourcing 을 따라,
Redux는 상태 변화가 일어나는 시점에 제약을 두어 상태 변화를 예측 가능하게 만들고자 시도합니다.

3가지 원칙

진실은 하나의 근원으로부터 

애플리케이션의 모든 상태는 하나의 저장소 안에 하나의 객체 트리 구조로 저장됩니다.

하나의 상태 트리만 가지고 있으면 디버깅에도 용이할 것이고, 개발 구현이 직관적일 것이다. 

 

하지만 Store를 여러개를 두는 것도 가능을 하다고 한다. 

아직 사용은 한번도 안해봤지만...

 

상태는 읽기 전용이다. 

상태를 변화시키는 유일한 방법은 무슨 일이 벌어지는 지를 묘사하는 액션 객체를 전달하는 방법뿐입니다.

이건 정말 그래야 한다고 생각한다. 

정해진 방식을 토대로 변경하는 것이 아닌 상태를 어디서든지 마음대로 변경이 가능하다면 

문제가 발생했을 때, 해결할 때 많은 시간이 걸릴 것 같다. 

 

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

액션에 의해 상태 트리가 어떻게 변화하는 지를 지정하기 위해 프로그래머는 순수 리듀서를 작성해야합니다.

이전 상태와 Action을 받아서 실행하면 언제나 똑같은 결과를 내놓는 순수함수여야 한다. 

이것도 당연한 이야기인 것 같다. 

 

당연한 이야기를 당연하게 구현하는 건 정말 어려운 일인 것 같다. 

 

용어집 

상태 

type State = any

Redux의 API에서 저장소에 의해서 관리되고 있는 하나의 상태값을 말한다. 

 

부끄러운 이야기지만 TypeScript를 하기 전까지만 해도 State란 부분을 정말 추상적으로 알고 있었다.

단순하게 리듀서에서 지정한 State의 묶음이라고 생각했다. 

어찌보면 그것도 맞는 말이다. 아니 이게 맞는 말이긴 하다. 당연하게도 

 

하지만 내가 말한 State의 묶음 이란 것은 State가 존재하지 않고 리듀서로 지정한 State를 

가지고 오기 위한 변수(?) 정도의 개념으로 이해했다는 것이다. 

 

하지만 TypeScript를 공부하면서 

export type RootState = ReturnType<typeof store.getState>;

getState를 통해서 실제 State의 타입을 알 수 있었다.

이게 정말 말로 설명하기 애매한 이해의 단계인 것 같다.

 

액션

type Action = Object

상태를 변화시키려는 의도를 나타낸다. 저장소에 데이터를 넣는 유일한 방법이다. 

액션을 통해서 상태가 변경되는 것은 아니다. 상태를 변경하기 위해서 액션을 사용하는 것이다. 

 

이 말도 애매모호한데, 액션은 함수가 아니라는 뜻이다. 

액션 자체가 상태를 변경시키는 것이 아니고 상태를 변경시키기 위한 Key가 된다. 

 

리듀서 

type Reducer<S, A> = (state: S, action: A) => S

누적된 값과 값을 받아서 새로운 누적값을 반환하는 함수이다. 

 

노적된 값은 State, 상태 객체를 나타내고 누적될 값은 액션이다. 

즉, State와 액션을 통해서 새로운 상태를 계산한다. 

 

리듀서는 반드시 같은 입력이 있으면 같은 결과물을 반환하는 순수 함수여야만 하고, 

상태값 변화 외 부수 효과를 가져서는 안된다. 

 

디스패치 함수

type BaseDispatch = (a: Action) => Action
type Dispatch = (a: Action | AsyncAction) => any

액션이나, 비동기 액션을 받는 함수이다. 필요에 따라 액션을 저장소에 보낼수도

보내지 않을수도 있다.

 

액션 생산자 

단순하게 액션을 만드는 함수이다. 

 

액션 생산자를 호출하면 액션을 만들어낼 뿐, 디스패치하지는 않는다. 

저장소를 변경하기 위해서는 디스패치를 통해서 변경해야 한다. 

 

비동기 액션

type AsyncAction = any

디스패치를 통해서 보내지는 값이지만, 리듀서에서 바로 받아들이진 않는다. 

비동기의 경우 디스패치 전에 미들웨어를 통해서 액션으로 변경한 뒤 전달해야 한다. 

 

사용하는 미들웨어를 여러개가 있는데, 대표적으로 saga, thunk가 있다. 

 

미들웨어 

type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch

디스패치 함수와 결합하여 개로운 디스패치 함수를 반환하는 고차함수이다. 

비동기 액션을 동기 액션으로 전환하기 위해서 사용된다. 

 

 

반응형

'React > 이론' 카테고리의 다른 글

[React] 브라우저의 렌더링 과정  (0) 2022.11.06
[React] Custom Hook  (1) 2022.10.22
[React] Flux  (1) 2022.10.13
[React] Redux - toolkit편  (1) 2022.07.22
[React] Redux - 기본편  (1) 2022.07.21