[TIL]Redux

김형주·2021년 5월 17일
0

Redux의 정의


Redux is a pattern and library for managing and updating application state, using events called "actions".

Redux는 actions라는 이벤트를 사용하여 애플리케이션의 상태를 관리하고 업데이트하는 라이브러리 패턴이다.

출처 : Redux Documentation

Redux는 간단하게 말하면, 전역범주에서 상태를 관리할 수 있도록 도와준다고 생각하면 쉽다. 어떤 애플리케이션을 만든다고 했을 때, Component Context에 상관없이 어디에서든 접근할 수 있는 단일 소싱의 상태관리체계를 구성한다고 보면된다.

웹 애플리케이션을 만든다고 했을 때, 우리는 다양한 상태를 관리해야할 필요성이 생긴다. 정말 간단한 것들 조차도 변화하는 상황들에 계속적으로 마주하게 되고, 이러한 상태정보들을 관리하는 것에 어려움을 겪으면 웹 어플리케이션은 곧잘 버그나 에러를 만나게 된다. 그 상태들은 영향을 끼치는 범위, 혹은 Scope에 따라서 Global state 혹은 Local State의 명칭으로 불리게 된다.

애플리케이션에서의 상태들은 유저의 인터렉션 작용이나 웹 내에서의 다양한 이벤트에 의해서 계속 변화하게 되는데, 상태를 추적하고 변화를 파악하는 것은 웹 서비스를 구축하는데에 있어서 가장 기본적이며 중요한 사항이다. 그럼에도 불구하고 다양한 컴포넌트로 구성된 웹 어플리케이션을 만들다보면 예기치 못한 에러나 충돌을 마주하게 되는데 대부분 상태를 추적하지 못해 코드가 충돌을 일으키는 상황이 많다. 이러한 상황에서 상태들을 통합적으로 관리하기 위해 만들어진 라이브러리가 Redux 이며, 이는 상태 관리(state management) 라이브러리의 일종이다.

Redux의 역할

다음은 React dev tool로 확인해본 실제 넷플릭스 웹애플리케이션의 컴포넌트의 모습이다. 하나의 어떤 기능을 구현해내기 위해서는 수많은 컴포넌트들이 지속적으로 중첩되어있는 wrapper hell의 구조를 띄고 있다는 것을 알 수 있는데, 이때 단순히 react만을 이용해서 전체 컴포넌트의 state들을 관리하려고 하면, 어느 depth에서 state가 관리되어야하는지만 판단하는데 수많은 시간이 걸리고 그 관계들을 정립하고 컴포넌트 계획을 수립하는데에만 하루종일 걸릴수도 있다.

이처럼 깊은 중첩으로 이루어진 컴포넌트 구조를 구현하는 경우에 Redux와 같은 통합 상태관리 라이브러리는 빛을 발한다. 전체 상태자체를 관리하는 저장소를 제공함과 동시해, props를 계속 밑으로 내려야만하는 top-down props문제나, props drilling과 같은 문제들을 쉽게 해결해 줄 수있다. 맨 밑에 있는 컴포넌트에서 최상단의 props를 사용하려고 한다면, 중간에 이 props들을 내려줘야하는 component들 모두에서 이를 위한 코드들을 적어 코드라인이 쓸데없이 길어지고 중간에 오류가 났을 때 어디에서 문제가 생긴지를 찾는데도 한 세월이 걸린다.

하지만 redux의 저장소를 이용한 state 관리 방법을 활용하면 상태 변화를 관리하는 것도 훨씬 더 수월해져 상태 변화와 관련된 에러들의 예측가능성이 높아지고, 전체 컴포넌트의 관리도 훨씬 수월해진다는 장점이 있다. state의 source를 store라는 지점에서 통합적으로 관리하기 때문에, props-drilling과 같은 경로를 추적할 필요도 없고, 즉시 참조해서 사용할 수 있다.

왜 Redux를 사용해야만 할까?

Redux는 위에서 계속 얘기한 것처럼 Global State로 대표되는 state management library다. 애플리케이션의 많은 부분에서 가로지르며 사용될 수 있는 state를 의미한다.

이 Redux라는 라이브러리 패턴은 내가 훨씬 더 쉽게 언제, 어디서, 왜, 그리고 어떻게 애플리케이션의 상태들이 업데이트 되었는지 쉽게 이해할 수 있도록 도울 수 있고, 그러한 상태변화가 발생했을때 어떻게 로직이 움직일지 파악하기도 훨씬 쉽다. redux는 예측이 어렵고 테스트하기 어려운 state의 상황을 훨씬 쉽도록 만들어 준다.

언제 Redux를 사용해야만 할까?

Redux는 통합상태관리체계이므로, 전체적인 상태를 관리할때 최적이다. 그렇지만, Redux는 이를 구현하기위해 단순한 state구조와 다르게 store를 구성하고, reducer를 선언하고, actions의 정의가 이루어져야하며, dispatch를 분기시켜야한다. 때에 따라서는 redux가 비효율적일 수도 있다.

공식 사이트에서는 다음과 같은 상황에 redux를 권장하고 있다.

  1. 만약 앱의 다양한 곳에서 엄청나게 큰 규모의 애플리케이션 상태를 필요로 하는 상황이 많다.
  2. 그 앱 상태가 시간이 지날때마다 반복적으로 업데이트되어야 한다.
  3. 특정 상태를 업데이트하는 논리가 너무 복잡하다.
  4. 앱의 코드베이스가 꽤 큰 규모이고, 많은 사람들이 함께 작업해야하는 상황이다.

위의 내용들을 요약해보면, 기본적으로 규모가 큰 애플리케이션에서 상태를 통합적으로 관리하기 위해 필요하다는 이야기다. 일부 컴포넌트가 담당하는 부분은 그 내부에서 자체적으로 state와 setState함수를 구성해서 관리해주고, 많은 곳에서 사용되는 state는 전반적으로 redux에서 관리하도록 하라는 이야기로 풀이된다.

Redux의 기본 개념

위의 GIF는 리덕스 공식문서에서 설명하고 있는 Redux의 작동을 다이어그램으로 나타낸 것이다.

UI에서 일어난 특정 컴포넌트 내의 event Handler에서 변화될 데이터를 인지하고, 이러한 component를 담고있는 component container에서 dispatch(action creator)형태로 store로 전송(dispatch)한다. store 내부의 reducer함수state = initialState, action 2개의 인자를 받아 actionpayload를 이용해 state의 값을 업데이트시킨다.

Redux의 배경 개념

상태 관리(state management)

  • state
    : 애플리케이션을 구동하는 데이터의 원천, 단일의 데이터 창구라고 보면된다.
  • view
    : 현 상태를 기반으로한 UI의 명시적인 표현이다.(현 상태의 UI)
  • actions
    : 상태에서 업데이트를 발생시키거나, 유저 인터렉션에 기반해서 앱 안에서 변화가 일어나는 이벤트를 의미한다.

이것은 단방향 데이터 흐름의 작은 예다.

  • 시간 중에 특정한 포인트 지점에서의 앱의 상태를 표현하는 것이 상태
  • UI는 그 상태에 기반해서 렌더된 결과물
  • 마우스 클릭이나 데이터 변동과 같은 무언가가 일어났을 때, 상태는 일어난 것에 기반해서 변화가 일어난다.
  • state가 변동되면 UI는 다시금 렌더링이 일어난다.

    actions는 state의 변화를 일으키고, state의 변화는 view의 렌더링을 일으키고 view에서의 interaction은 actions의 변화를 일으키고...`

불변성(immutable)

https://daveceddia.com/react-redux-immutability-guide/
정리해두기


그리고 내가 이해한 Redux 작동원리를 그림으로 나타낸 것이다.

  1. Component에서 전역으로 구성된 store의 getState()메소드를 이용해서 현재 Store의 State를 가져올 수 있다. 리턴 값으로 현재 State값을 가져온다.
  2. Store의 subscribe(함수명)메소드를 이용해서, 상태변경에 따라 자동으로 해당 함수(컴포넌트)를 실행하도록 설정 등록할 수 있다.
  3. Store의 dispatch는 전달인자로 상태변경정보를 가지고 있는 Action을 받아서,dispatch(Action creator) 이러한 형태로 action을 store의 reducer에게 전달한다.
  4. reducer함수는 받아온 actiontype(행위의 종류)에 따라, 분기해서 현재 상태를 action에서 받아온 정보로 갱신한 새로운 객체를 store의 state로 다시 전달한다.
  5. 기본적으로 reducer함수는 외부 context에 영향을 받지 않고 오로지 인자를 가지고, 변경한 값만 그대로 리턴하는 pure function(순수 함수)이다.

Store


A store holds the whole State tree of Your application. The only way to change the state inside it is to dispatch an action on it.

스토어는 애플리케이션 전체 상태트리를 가지고 있다. 스토어 안의 상태를 변경하는 유일한 방법은 store에 action을 dispatch하는 것 뿐이다.

위 글은 Redux 공식문서에 적혀있는 Store의 첫 문장을 가져온 것이다. 말 그대로, Store라는 것은 앱 내의 상태정보를 가지고 있는 보관소(하지만 일반객체)이며, action을 인자로 dispatch를 이용함으로써만 상태를 변경할 수 있다. Store라는 것은 이전의 Pure react에서 class Component에서만 가지고 있던 this.state를 전역 상태(global)로 확대해서 모든 컴포넌트에서 접근할 수 있도록 만들어주는 라이브러리의 새로운 객체다.

Store를 생성하는 방법

// `createStore`함수를 이용해서 새로운 Redux store를 생성한다.
// 그리고 `counterReducer`함수를 이용해서 업데이트에 이용할 수 있다.
const store = Redux.createStore(counterReducer);

Store가 가지고 있는 기본 메소드

- store.getState()

애플리케이션의 현재 상태트리를 리턴한다. store의 바로 직전 reducer에 의해 리턴된 값과 동일하다.

- store.dispatch(action)

action을 발송한다. dispatch는 state 변경을 유발하는 유일한 방법이다. state를 변경하기 위해선 무조건적으로 dispatch()를 이용해야만 한다.
store의 reducing 함수는 최근 getState 메소드 결과(state 현재값)와 주어진 action과 동시에 불러진다. (=== reducing함수의 인자로 state 현재값action을 받는다.)
그리고 dispatch()의 리턴 값은 변화된 바로 다음 상태값이 된다.
값이 바뀌고 나면 change listeners에게 바로 알려진다.(상태 변경을 알린다.)

전달인자

action (객체)
애플리케이션에 적합한 변경 사항을 설명하는 일반 객체다. actions는 store 안으로 데이터를 집어넣는 유일한 방법이다. 그래서 어떤 데이터(UI 이벤트, 네트워크 콜백, 또는 웹소켓과 같은 기타 다른 소스의 모든 데이터는 결국 action으로만 전달되어야 한다. action은 해당 작업 유형을 type으로 지정한 키-값 쌍을 가지고 있으며, 각 유형은 상수로 정의하고 다른 모듈에서 가져올 수 있다.

//action 예시
const ADD_NUM = "ADD_NUM";
function add(num1, num2){
  return {
    type : ADD_NUM,
    payload : {
      num1 : num1,
      num2 : num2,
    };
  };

- store.subscribe(listener)

change listener를 붙인다. 한 action이 dispatch되면, subscribe가 불려진다, 그리고 상태 트리의 일부는 아마도 잠재적으로 변경된다. 아마도 getState()를 통해서 현재 상태트리를

store.replaceReducer(nextReducer)

const store = createStore(reducer 함수)

다음과 같은 형태로 선언할 수 있으며, reducer은 개인이 지정해서 데이터 저장 방식을 정의해둘 수 있다. create, re

profile
만물에 관심이 많은 잡학지식사전이자, 새로운 도전을 꿈꾸는 주니어 개발자 / 잡학지식에서 벗어나서 전문성을 가진 엔지니어로 거듭나자!

0개의 댓글