리덕스 공부 #1

min Mt·2020년 4월 29일
0
post-thumbnail

리덕스 공식 튜토리얼 정리

Introduction

리덕스 없이 순수 리액트로 프로젝트를 해보니, 스테이트 관리가 정말 힘들었다. 자식 컴포넌트에서 Inverse Data flow로 state를 바꾸는 것도 나중에 가니 헷갈리고, 자식 컴포넌트들에게 필요한 값들만 props로 전달하는 것도 귀찮고 헷갈리고 그랬다. 그래서 Redux를 한번 써보기 위해 기초부터 꼼꼼하게 공부하면서 정리하는 기록.

Motivation

리덕스는 스테이트 관리를 도와주는 라이브러리다.
스테이트를 변형하여 동적인 앱을 만드는 것 = GOOD
비동기적 프로그래밍으로 부드러운 앱을 만드는 것 = GOOD
하지만 둘이 같이 된다면 너무 복잡하고 어려워진다. 즉, 생각 못한 결과가 나오는 경우가 생길 수 있다.
이 둘을 같이 사용하여 예측가능한 state mutation 을 도와주는 것. 이게 Redux 다.

Redux attempts to make state mutations predictable.

Core Concepts

ㅋㅋ 이 핵심 개념 파트를 다시 읽으니 웃긴 부분이 많다.
리덕스를 처음 배우기 전에 리덕스가 뭔가 대단한 일, 문서에서 말하는 마법을 부려줄 것만 같아서, 오히려 리덕스를 접근하는게 어렵게 느껴졌다. 하지만 문서에서 자꾸 말하는대로 리덕스가 마법을 부려주는게 아니다.

리덕스는 store에 들어있는 state를 언제 어떻게 변형할지에 관한 가이드를 준다고 생각하면 될듯하다.

문서에 나온 예를 살펴보면

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

여기 ToDo 앱의 state가 있다. 이 state는 store에 저장되어 있다.
이 state를 변경하려면 action을 통해야 한다.
action은 Plain Javascript Object이다.

//actions
{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

위 오브젝트들이 action들이다. type과 data를 가지고 있다. 이 action들은 단순히 무슨 일을 할지에 대한 정보만 적혀있다고 보면 된다. 그리고 이 action을 storedispatch하면 action에 맞는 작업이 이루어 진다. 이 작업을 하는 실제 함수가 바로 reducer이다. 리듀서는 state와 action 을 인자로 받아 새로운 state를 반환한다. 인자로 받은 Previous state는 바꾸지 않는다. 다음 코드는 이 예제의 리듀서들이다.

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter
  } else {
    return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([{ text: action.text, completed: false }])
    case 'TOGGLE_TODO':
      return state.map((todo, index) =>
        action.index === index
          ? { text: todo.text, completed: !todo.completed }
          : todo
      )
    default:
      return state
  }
}

리듀서를 역할과 기능에 맞추어 나누어 작성하는 것이 관리하기에 용이해서 위처럼 visibilityFiltertodos로 나누어 작성한다. 그리고 이를 하나의 리듀서로 합친다.

function todoApp(state = {}, action) {
 return {
   todos: todos(state.todos, action),
   visibilityFilter: visibilityFilter(state.visibilityFilter, action)
 }
}

이렇게 하면 reducer가 state를 가지고 새로운 state를 반환할때, previous state는 변하지 않으므로 예측 가능한 state관리가 가능하다. 뿐만 아니라 React에서는 state를 전역적으로 관리할 수 있게 되어서 그게 큰 장점이다.

Three Principle

Motivation에서 말한 예측 가능한 state관리를 위해선 다음 세가지 원칙을 지켜야 한다.

1. Single source of truth

쉽게 말해 store가 하나만 있어야 된다는 것.

2. State is read-only

state는 변해야 하는 건데..?
말이 헷갈리는데 읽어보면 state가 뷰나 네트워크 콜백 등을 통해 직접적으로 수정/작성 하면 안된다는 것이다. 이 state는 오직 action을 통해서만 변경된다.

3. Changes are made with pure functions

순수(?) 함수라는 것이 무엇인지 생각해보자. 중학교때 배우는 함수 정의를 생각해보면 된다.
함수의 본질은 A가 들어가면 B라는 결과가 나오는 1:1 Mapping 알고리즘이다.
A가 들어갔는데, A는 C로 바뀌고 B라는 결과를 반환하면 순수한 함수가 아니다.
즉, state를 변경하는 reducerPrevious StateAction 을 입력받아 새로운 State를 반환한다. Previous State나 Action 을 변형시키지 않는다.

흠, 만약 Redux를 처음 공부하는 사람들은 action, previous state, reducer, store는 뭔지 전혀 모르실텐데요. 만약 Redux를 처음 접하고 위 세가지 원칙을 왜 지켜야 하는지 이해가 안가시는 분들은 공식문서에 나오는 모든 튜토리얼 등 공부를 다 끝내고 다시 한번 위 세 가지 원칙이 왜 지켜져야 하는지 생각해보시면 좋을듯 합니다.

Actions

action 은 단지 type과 data 따위를 담고있는 plain javscript object이다.
다음시간에 하자..

profile
안녕하세요!

0개의 댓글