[Redux] Redux(1) - Flux의 구현체 Redux

권준혁·2020년 11월 1일
0

Git

목록 보기
8/8
post-thumbnail

안녕하세요

Redux는 자바스크립트를 위한 상태관리 프레임워크입니다.
리액트에서 상태값을 하위 컴포넌트에 전달할 때, 그 깊이가 깊어질 수록 복잡도가 올라갑니다. ContextAPI를 사용할 수도 있지만 이 경우도 여러개를 중첩해서 사용하게되면, 전달하는 컴포넌트나 사용하는 컴포넌트에서도 마찬가지로 복잡도가 올라갑니다.

반대로 하위 컴포넌트에서 상위 컴포넌트로 값을 전달해야 하는경우에는 이벤트를 하위 컴포넌트에 전달해 사용하는데, 이 경우에도 마찬가지로 복잡도가 올라갑니다.

그리고 이런 동일한 기능을 위한 반복되는 작업은 지칩니다.

Redux는 이러한 상태값 관리를 직렬화 해서 하나의 객체에서 관리합니다.
모든 컴포넌트는 이 하나의 객체에서 상태값을 참조하게 되어 이해하기쉬울 뿐 아니라 상태값 제어에 관한 모든 것을 하나의 객체를 통해 할 수 있기 때문에 관심사 분리가 용이하며 테스트 환경도 좋아집니다.

Redux의 세가지 원칙

  • 전체 상탯값을 하나의 객체에 저장한다.

    • TextInput이나 애니메이션을 위한 상탯값은 컴포넌트 내에서 관리하는 것이 더 좋을 수 있으며, 프로그램의 일부 상태만 리덕스를 활용해도 됩니다.
  • 상탯값은 불변객체다.

    • React의 state와 마찬가지로 상태 객체의 일부만 수정하는 push등의 메서드를 사용하면 버그가 발생할 수 있습니다.
    • 이전 상탯값과 이후 상탯값을 비교 후 변경점을 파악할 때, 메모이제이션과 같은 기능을 사용할 때 불변객체를 사용하는 것이 더 유리합니다.
  • 상탯값은 순수함수에 의해서만 변경되어야 한다.

    • 순수함수는 같은 입력값이면 같은 결과값을 출력하는 함수입니다.
    • 순수함수는 타이머, 랜덤, Date등이 반환값에 영향을 주면 순수함수가 아닙니다.

Flux의 구현체 Redux

MVC패턴을 사용하던 Facebook에서는 고질적인 문제를 해결하기 위해 Flux아키텍쳐를 만들었습니다. 규모가 큰 서비스에서는 MVC패턴이 보다 Flux구조가 좋다고 말합니다.

그리고, Redux는 flux아키텍쳐를 구현체들 중 하나로 React와 잘 어울립니다.

flux 아키텍쳐

  • Action

    Action은 사용자와 애플리케이션간의 상호작용이나 타이머, 웹소켓등 에서 발생하는 이벤트라고 할 수 있습니다.
    Action은 고유한 이름(type)과 포함하는 데이터(payload)를 가지고 있습니다.

    const add = {
    type: "USER_ADD",        // type
    payload: {            // payload
       name: "junhyuk",
       age: "70"
    }
    }
  • Dispatcher

    Dispatcher는 Action을 Store에 전달하는 역할입니다.
    store의 상태(앱 전체의 상태)는 Dispatcher에 의해서만 변경되며, 이 것이 단방향 흐름을 보장해줍니다.

  • store

    store는 애플리케이션의 거의 모든 상태를 가지고 있습니다. 개발자가 일부러 컴포넌트 내에서만 사용할 목적으로 store에서 관리하지 않도록 한 경우는 제외입니다.
    store의 데이터는 Dispatcher를 통해서만 변경될 수 있습니다.

  • View

    사용자가 보는 화면입니다. 이 화면에서 앱과 사용자의 상호작용, 이를테면 버튼 클릭등 이벤트(Action)가 발생하면 Dispatcher에 등록된 콜백함수를 통해 Store에 전달되어 상태값이 변경됩니다.
    그리고 상태값 변경에 따른 View도 함께 변경됩니다.
    이런 재귀적인 흐름이 Flux의 기본구조입니다.

React는 이 구조에서 View를 담당합니다.
그리고 Redux가 나머지 Action, Dispatcher, Store를 담당합니다.

Redux

Redux와 React가 잘 조합되지만 Redux가 React만을 위해 만들어진 것은 아닙니다.
Redux는 JavaScript앱을 지원합니다.

npm i redux

Flux와 Redux의 비교

공통점은 Action, Dispatch, Store, View가 존재한다는 것, 단방향 데이터 플로우를 가지는 것, View와 결합되지 않았다는 것입니다.
가장 큰 차이점은 Redux가 Reducer를 필수로 가져야 한다는 것입니다.

Redux를 시작할 때 가장 먼저 하는 것은 reducer를 작성하고, 이 reducer로 Store를 생성하는 것입니다.

import { createStore } from 'redux'

Reducer함수는 state와 action을 매개변수로 가집니다.
매개변수에 초기값을 설정할 수도 있고 따로 변수로 작성해도 됩니다.

const INITIAL_STATE = {
    ...
}
function counter(state=INITIAL_STATE, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

그런다음
Store를 생성해주는 redux의 함수 createStore의 인자로 방금 작성한 reducer를 넣어 초기화합니다.

let store = createStore(counter)

store의 상탯값이 변경되었다면 View역할을 맡고있는 React에게 알려줘야합니다. store가 갖고있는 메서드 들중 subscribe를 이용합니다.

subscribe메서드는 action이 dispatch되고, store가 변경될 때마다 실행할 콜백함수를 정의할 수 있는데 React에서는 state가 변경되면 자동으로 업데이트되므로 setState를 콜백으로 넣어 View에서 변경됐음을 사용자에게 알릴 수 있습니다.

store.subscribe(()=>setState(updated))

여기서 store.getState()를 이용해 로그를 출력할 수도 있고, setState를 할 수도 있습니다.
store.subscribe() 함수는 구독을 해제하는 함수를 리턴합니다.
따라서 별도의 패키지 (react-redux)를 사용하지 않는 경우 이런 패턴으로 사용됩니다.

componentDidMount() {
    this.unSubscribe = store.subscribe(() => console.log(store.getState()))  
}
componentDidUnMount() {
    this.unSubscribe()
}

store의 상태값을 변경하는 유일한 방법은 dispatch(action)입니다.
action은 type속성으로 고유한 상수를 가진 객체입니다.

store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })

여기서 Action은 { type: 'INCREMENT' }{ type: 'DECREMENT' } 입니다.

store.dispatch(action)

dispatch 함수로 action을 store에 넘겨주는 형태입니다.

전체 코드

import { createStore } from 'redux'; // redux의 createReducer

function counter(state = 0, action) { // reducer작성
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
};
let store = createStore(counter);  // reducer로 store초기화
store.subscribe(() => console.log(store.getState())); // 구독

// dispatcher에 action을 이용해 store상탯값 변경
// action.type에 따라 store가 다른 기능을 수행할 수있음
store.dispatch({ type: 'INCREMENT' });  
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });

state의 초기값은 0입니다.
store.dispatch()가 실행될 때마다 store의 콜백함수가 실행됩니다.
store.getState()는 store의 상탯값을 리턴하는 함수입니다.
따라서 결과는 아래와 같습니다.

1
2
1

다음 포스팅에서 React와 Redux를 함께 사용하는 법을 알아보겠습니다.

profile
웹 프론트엔드, RN앱 개발자입니다.

0개의 댓글