Redux

프최's log·2020년 10월 15일
0

study

목록 보기
26/59
post-thumbnail

What is Redux?

공식문서

 Redux 공식 홈에서는 자바스크립트 애플리케이션을 위한 '예측가능한 상태 컨테이너'(state container for JS) 라고 표현한다. 컴포넌트와 상태를 분리한다. 왜 분리를 할까? 관리해야할 상태가 컴포넌트에서 분리되면 Class 컴포넌트가 단순 함수 컴포넌트로 만들 수 있는 장점이 있기 때문이다. 더불어 Redux는 React와 같이 사용되지만, React 없이도 독립적으로 사용할 수 있는 상태 관련 라이브러리 다. 그리고 Flux 패턴을 적용한 라이브러이다.

Flux 패턴?

Flux 패턴은 MVC(Model-View-Controller)의 문제점을 보완할 목적으로 만들어진 패턴이다. MVC에서 어떤 문제점이 있었던 것일까?

MVC 패턴 : UI, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴 - MDN

페이스북 개발팀에 따르면 구조가 복잡해지게 될 경우, 새로운 기능을 추가할 때마다 발생하는 문제점에 대해 '예측이 불가'하고 '테스트가 힘들어지는' 등의 문제가 생겨 결국 개발 속도에도 지연이 생기는 문제점이 생기게 되었다. 이를 보완하기 위해 내놓은 패턴이 바로 Flux 패턴이다.

Flux 패턴을 이용해서 규모가 크거나, 급격히 증가할 것으로 예상되는 상황을 '단방향 데이터 흐름'을 통해 '애플리케이션의 복잡도'를 크게 증가시키지 않을 수 있다.

참조사이트
Flux
[React] Redux(1) - Flux Design Pattern
Flux와 Redux : MVC의 한계를 극복한 단순한 데이터 모델

Redux의 구성과 흐름

 Redux에서 가장 중요한 개념인 Store가 있는데, 이 안에서 실제 상태(state)를 관리한다.

 그럼 왜 Store 안에 담아서 이것을 관리하는 걸까?

 복잡한 구조의 컴포넌트, 이를테면 중첩 안의 중첩 컴포넌트가 어떤 유저의 정보를 필요로 할 경우, 과도한 props drilling(프로퍼티 내려꼽기)의 문제가 발생할 수 있다. 유저 정보를 요청하기 위해서 계속 위로 state를 올려보내고 내려보내는 상황이 발생하는 것. 이렇다보니 컴포넌트가 접근할 수 있는 '공용 스토어'를 이용하게 한 것이다.

 Store에는 Store를 관리하는 관리자인 Dispather가 존재한다. 이를 이용해 상태를 변경한다.

흐름
1.특정 컴포넌트가 스토어로 user 정보(상태)를 요청한다.
2.getState 를 통해 user 정보가 render 된다.
3.웹에서 상태가 변경되면 action을 통해 그 내역서를 dispatch에 전달하고
4.dispath는 reducer를 거쳐 user 정보 상태를 변경한다. = setState의 역할 → 이때 실 정보, 즉 원본은 바뀌지 않는다.

이러한 상태 관리(state Management)를 진행해주는 라이브러리가 Redux 이다.

그림은 생활코딩을 참조해서 필자가 이해하고자 하는 흐름을 중점적으로 구성한 Redux 흐름도이다.


Redux의 기본개념 : 3가지 원칙

  • Single source of truth
  • State is read-only → 이 원칙을 지키기 위해 action(순수 JS 객체)를 이용한다.
  • Changes are made with pure functions

Store : Single source of truth

컴포넌트가 요청하는 state를 관리하는 '오직 하나의 공간'이다.

Action

액션은 애플리케이션에서 저장소로 보내는 데이터 묶음으로 변경사항을 적용하기 위한 유일한 방법이다. 액션을 보낼 때, 스토어로 변경할 state 객체(plain object)를 보내는데, 즉 Javascript의 새로운 객체({}) 형태로 하나의 '주문서'처럼 이해하면 쉽다.

  • 액션은 type속성을 가져야한다.★
    이는 어떤 형태의 액션이 실행될지 나타내는 표현이다.

Reducer : pure function

그렇다면 이 action을 상태트리에 어떻게 보내야하는가? 바로 리듀서(Reducer)를 이용해야하는데 이는 사용자가 만드는 함수다. action과 기존 state가 주어지면, '업데이트 내역'을 반영하여 갱신된 state를 요청한 컴포넌트로 전달하는 역할을 한다.

형태
;(previousState, action) => newState

리듀서를 보낼 때 절대 하지 말아야할 것들 :

  • 인수들을 변경(mutate)하기;
  • API 호출이나 라우팅 전환같은 사이드이펙트를 일으키기;
  • Date.now()나 Math.random() 같이 순수하지 않은 함수를 호출하기.

사이드이펙트
순수하게 output을 해야하는데 그외의 일을 하는 것 - API 호출, 라우팅 전환
만약 이 사이드이펙트를 하고자 한다면, 비동기 액션 미들웨어를 이용한다.

처음 리듀서를 undefined로 호출한다. 이를 통해 초기 상태를 반환할 수 있는 기회가 형성된다.

// 초기 상태
const initialState = {
  visibilityFilter: VisibilityFilters.SHOW_ALL,
  todos: []
}

function todoApp(state, action) {
switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state // 우리가 작성한 초기상태를 반환한다.(기본값 default)
  }
}

상태변화를 할때는 Object.assign을 통해 복사본을 형성한다. MDN - Object.assign

  • 첫번째 인수는 반드시 빈 객체를 전달해야한다. 첫번째 인수를 변경해선 안되므로!(immutable)
  • 만약 빈객체를 활용하지 않을 경우, spread 문법 사용할 수 있다.
    Object.assign({...state}, {currentUser: { name: "Dinel" }})

객체가 중첩되어있을 경우

아래와 같이 객체가 중첩되어있으면, 모든 중첩 단계를 적절히 복사하고 업데이트 시켜야한다.

currentUser: {
  name: "김코딩",
  company: {
    name: "Coggle",
    department: "Development",
    role: {
      name: "Software Engineer",
    }
  }
}
  
// 중첩단계 복사 진행
let newState = Object.assign({...state}, {
currentUser: {
  ...state.currentUser,
  company: {
    ...state.currentUser.company,
    role: {
      name: "CEO",
    }
  }
}
})  
newState; // 위 state 에서 role만 변경된 것을 확인할 수 있다.

Redux 저장소의 API

store가 지니고 있는 API는 subscribe, dispatch, getState 로 보통 저장소의 상태변화를 일으킬 때, dispatch를 이용하게 된다.

  • getState() : 상태에 접근
  • dispatch(action) : 상태를 수정
  • subscribe(listener) : 리스너 등록

여러 리듀서를 1개로 합치는 combineReducers()

서로 다른 리듀싱 함수들을 값을 가지는 객체로 받아서 createStore에 넘길 수 있는 리듀싱 함수로 바꿔준다.


Redux의 장점

  • 상태 예측 가능
  • 유지보수 용이
  • 시간여행을 할 수 있어서 디버깅에 유리하다(action과 state 로그 기록할 경우)
    → Redux Dev 툴을 사용하여 효율적으로 상태변화를 파악할 수 있다.
  • 테스트를 붙이기 쉽다

(내용추가예정)

Presentational 컴포넌트와 Container 컴포넌트

redux-thunk 작동 원리 파악하기

이 미들웨어를 사용해서 액션 생상자가 객체 대신 함수를 반환할 수 있다.


설치없이 Redux 사용하기

예제 활용이나 아직 npm 활용이 버거울 경우, reduxcdn-redux 를 통해서 설치 없이 활용할 수 있다.

script 태그를 html 내 head 안에 넣어두고서 활용하게 되면 아래와 같이 redux를 쓸 수 있다.

  설치없이 사용한 Redux 예제(생활코딩 참조)

만약 redux dev 툴도 함께 활용하고자 한다면?

로컬에서는 server를 키지 않으면 활용이 힘들기 때문에, createStore 안에 간단하게 코드 한줄을 추가해서 dev툴도 활용할 수 있다.

const store = createStore(
   reducer, 
   window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
 );

자세한 내용 → redux-devtools-extension


참조
presentation / container 컴포넌트 번역글
벨로퍼트
리덕스 왜 쓰는건데?


생활코딩 - Redux
생활코딩 - React & Redux

profile
차곡차곡 쌓아가는 나의 개발 기록

0개의 댓글