TIL. 리덕스로 상태관리하기

chloe·2021년 3월 3일
0

TIL

목록 보기
53/81
post-thumbnail

🐤리덕스로 상태관리하기

리덕스는 자바스크립트를 위한 상태 관리 프레임워크다. 리액트를 사용하는 많은 프로젝트에서 리덕스도 같이 사용하는데 이유는 왜일까?

  1. 컴포넌트 코드로부터 상태 관리 코드를 분리할 수 있다.
  2. 서버 렌더링데이터 전달이 간편하다.
  3. 로컬 스토리지데이터를 저장하고 불러오는 코드를 쉽게 작성할 수 있다.
  4. 같은 상탯값을 다수의 컴포넌트에서 필요로 할 때 좋다.
  5. 부모 컴포넌트에서 깊은 곳에 있는 자식 컴포넌트에 상탯값을 전달할 때 좋다.
  6. 알림창과 같은 전역 컴포넌트의 상탯값을 관리할 때 좋다.
  7. 페이지가 전환되어도 데이터는 살아있어야 할 때 좋다.

🐽 리덕스 사용 시 따라야 할 세 가지 원칙

  1. 전체 상탯값을 하나의 객체에 저장한다.
  2. 상탯값은 불변객체다.
  3. 상탯값은 순수 함수에 의해서만 변경되어야 한다.

하나의 객체에 프로그램의 전체 상탯값을 저장한다

전체 상탯값이 하나의 자바스크립트 객체로 표현되기에 활용도가 높아진다. 리덕스를 사용하면 하나의 객체를 직렬화해서 서버와 클라이언트가 프로그램의 전체 상탯값을 서로 주고받을 수 있다.
최근의 상탯값을 버리지 않고 저장해 놓으면 실행취소다시 실행 기능을 쉽게 구현할 수 있다.

하지만, 프로그램의 전체 상탯값을 리덕스로 관리하는 것은 쉬운 일이 아니다. 애니메이션을 위한 데이터나 문자열 입력창의 현재 상탯값은 컴포넌트에서 관리하는게 더 나을 수도 있다. 프로그램의 일부 상태만 리덕스를 활용해도 된다.

상탯값을 불변객체로 관리한다
상탯값은 오직 액션객체에 의해서만 변경된다.

const incrementAction={
  type:"INCREMENT",//1
  amount:123,//2
};
const conditionalIncrementAction={
  type:"CONDITIONAL_INCREMENT",//1
  amount:2.  //2
  gt:10,    //2
  lt:100,  //2
};
store.dispatch(incrementAction);  //3
store.dispatch(conditionalIncrementAction);//3

1.액션 객체는 type 속성 값이 존재해야 한다. type속성 값으로 액션 객체를 구분한다.
2.type속성 값을 제외한 나머지는 상탯값을 수정하기 위해 사용되는 정보다.
3. 액션 객체와 함께 dispath메서드를 호출하면 상탯값이 변경된다.

리덕스의 상탯값을 수정하는 유일한 방법은 액션 객체와 함께 dispatch메서드를 호출하는 것이다.
상탯값은 dispatch메서드가 호출된 순서대로 리덕스 내부에서 변경되기에 상탯값이 변화되는 과정을 쉽게 이해할 수 있다.

상탯값 수정이라는 목적만 놓고 보면 불변객체를 사용하는 것보다는 상탯값을 직접 수정하는 게 더 빠르다. But, 이전 상탯값과 이후 상탯값을 비교해서 변경 여부를 파악할 때는 불변 객체가 훨씬 유리하다. 리액트 렌더링 성능을 올리는 데도 유리하다.

리액트에서 엄청 깊은 구조로 되어있는 객체를 업데이트를 할 때 기존의 객체는 건들이지 않고 Object.assign을 사용하거나 spread 연산자를 사용하여 업데이트하곤 한다. 리덕스에서도 마찬가지!리덕스에서 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경되는 것을 감지하기 위하여 shallow equality검사를 하기 때문이다. 이를 통하여 객체의 변화를 감지할 때 객체의 깊숙한 안쪽까지 비교를 하는 것이 아니라 겉핥기 식으로 비교를 하여 좋은 성능을 유지할 수 있는 것이다.

오직 순수 함수에 의해서만 상탯값을 변경해야 한다
리덕스에서 상탯값을 변경하는 함수를 리듀서라고 부른다.

(state,action)=>nextState

리듀서는 이전 상탯값과 액션 객체를 입력으로 받아서 새로운 상탯값을 만드는 순수 함수다. 순수 함수는 부수효과(side effect: 전역 변수값을 수정한다거나 API 요청을 보내는 등 함수 외부의 상태를 변경시키는 것을 말한다)를 발생시키지 않아야 한다. 또한 순수함수는 같은 인수에 대해 항상 같은 값을 반환해야 한다.

리듀서는 순수 함수이기에 같은 상탯값과 액션 객체를 입력하면 항상 똑같은 다음 상탯값을 반환한다. 따라서 실행된 액션객체를 순서대로 저장했다가 나중에 똑같은 순서로 dispatch메서드를 호출하면 쉽게 리플레이 기능 구현할 수 있다.

리덕스의 네가지 요소(액션,미들웨어,리듀서,스토어)

1.액션

액션은 type속성값을 가진 자바스크립트 객체다.

액션을 발생시키는 예제 코드를 봐보자.

store.dispatch({type:'ADD',title:'영화 보기',priority:'high'});
store.dispatch({type:'REMOVE',id:123});
store.dispatch({type:'REMOVE_ALL'});

각 액션은 고유한 type속성 값을 사용해야 하는데 ADD라는 단어 하나만으로는 중복 가능성이 높다. type이름의 중복을 피하기 위해 다음과 같이 접두사를 붙이는 방법이 많이 사용된다.

store.dispatch({type:'todo/ADD',title:'영화 보기',priority:'high'});
store.dispatch({type:'todo/REMOVE',id:123});
store.dispatch({type:'todo/REMOVE_ALL'});

type속성 값은 리듀서에서 액션 객체를 구분할 때도 사용되기에 상수 변수로 만드는게 좋다.

export const ADD='todo/ADD';
export const REMOVE='todo/REMOVE';
export const REMOVE_ALL='todo/REMOVE_ALL';
// 1 
export function addTodo({title,priority}){
  return{type:ADD,title,priority};
}
export function removeTodo({id}){
  return{type:REMOVE,id};
}
export function removeAllTodo(){
  return{type:REMOVE_ALL};
}  
//2

1에서 type 이름을 상수 변수로 만들었다. 이 변수는 리듀서에서도 필요하기에 export 키워드를 이용해서 외부에 노출한다. 2의 액션 생성자 함수도 외부에서 노출해야 하므로 외부로 노출한다.

2. 미들웨어

미들웨어는 리듀서가 액션을 처리하기 전에 실행되는 함수다. 디버깅 목적으로 상탯값 변경 시 로그를 출력하거나, 리듀서에서 발생한 예외를 서버로 전송하는 등의 목적으로 미들웨어를 활용할 수 있다. 리덕스 사용 시 특별히 미들웨어를 설정하지 않았다면 발생한 액션은 곧바로 리듀서로 보내진다.

const myMiddleware=store=>next=>action=>next(action);

미들웨어는 함수 세 개가 중첩된 구조로 되어 있다. 화살표 함수가 연속으로 표현된 코드가 익숙하지 않는다면 헷갈릴 수 있다.

3. 리듀서

리듀서는 액션이 발생했을 때 새로운 상탯값을 만드는 함수다.

function reducer(state=INITIAL_STATE,action){//1
  switch(action.type){
      //...
    case REMOVE_ALL://2
      return{
        ...state,
        todos:[],
      };   //3
    case REMOVE:
      return{
        ...state,
        todos: state.todos.filter(todo=>todo.id!==action.id),
      };
      default;
      return state;//4
  }
}

const INITIAL_STATE={todos:[]};

리덕스는 스토어를 생성할 때 상탯값이 없는 상태로 리듀서를 호출하므로 1 매개변수의 기본값을 사용해서 초기 상탯값을 정의한다. 2 각 액션 타입별로 case문을 만들어서 처리한다. 3 상탯값은 불변 객체로 관리해야 하므로 수정할 때마다 새로운 객체를 생성한다. 전개 연산자를 사용하면 상탯값을 불변 객체로 관리할 수 있다. 4 처리할 액션이 없다면 상탯값을 변경하지 않는다.

4. 스토어

스토어는 리덕스의 상탯값을 가지는 객체다. 액션의 발생은 스토어의 dispatch메서드로 시작된다. 스토어는 액션이 발생하면 미들웨어 함수를 실행하고, 리듀서를 실행해서 상탯값을 새로운 값으로 변경한다.
리덕스의 첫 번째 원칙에서 애플리케이션의 전체 상탯값을 하나의 스토어에 저장하라고 했다.
단순히 데이터의 종류에 따라 구분하기 위한 용도라면 나중에 설명할 combineReducer함수를 이용하면 된다. 그러나 특별한 이유가 없다면 스토어는 하나만 만드는 것이 좋다.

참고: 실전리액트프로그래밍

profile
Front-end Developer 👩🏻‍💻

0개의 댓글