TIL78.Redux

조연정·2021년 3월 23일
0

리덕스 라이브러리가 어떤 방식으로 작동하는지 알아보자.

리덕스의 구성

1.store

데이터들을 저장해놓는 공간으로 한 애플리케이션 당 하나의 스토어만 가진다. 스토어 안에는 현재 앱 상태인 state와 reducer 외 내장 함수들이 존재한다.
import구문을 이용해 리덕스에서 해당 함수를 불러올 수 있고, 함수의 파라미터에는 리듀스 함수가 필요하다.

2.action

단방향을 유지하기 위한 장치, state에 변화가 필요할 때 객체의 형태로 액션을 발생시킨다. 액션객체는 type필드를 반드시 가지고 있어야 하고 이 값은 액션의 이름이다. 액션의 이름은 주로 대문자로 작성하고 고유해야 한다.

3.dispatch

스토어의 내장함수 중 하나로 액션을 발생시키는 역할을 한다.
dispatch(action) -> 함수 안에 액션을 파라미터로 전달한다.

4.reducer

새로운 객체를 만들어서 store의 기존 state가 새로운 객체로 대체된다.
액션을 만들어서 발생시키면 리듀서는 현재 상태와 전달받은 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해준다.
*액션과 리듀서는 짝꿍

리덕스 사용 예제

//스토어 생성
const { createStore } from 'redux';
const store = createStore(reducer);

//리듀서 함수-액션 타입에 따라 다른 일을 처리
const reducer = (prevState, action) => {
  switch (action.type) {
    case "LOG_IN":
      return {
        ...prevState,
        user: action.data,
      };
    case "LOG_OUT":
      return {
        ...prevState,
        user: null,
        posts: [],
      };
    case "ADD_POST":
      return {
        ...prevState,
        posts: [...prevState.posts, action.data],
      };
    default:
      return prevState;
  }
};

// 로그인 전, 게시글도 없는 초기상태 정의
const initialState = {
  user: null,
  posts: [],
};

const nextState = {
  ...initialState,
  post: [action.data],
};
//게시물이 추가적으로 들어오는 경우

// const nextState = {
//   ...initialState,
//   post: [{ id: 1 }, { id: 2 }],
// }; =

const nextState = {
  ...initialState,
  post: [...initialState.posts, action.data],
  //       기존데이터            , 새로운 데이터
};

const store = createStore(Reducer, initialState);

// action함수 정의 - type은 액션의 이름
const login = (data) => {
  return {
    type: "LOG_IN",
    data,
  };
};

const logout = () => {
  return {
    type: "LOG_OUT",
  };
};

const addPost = (data) => {
  return {
    type: "ADD_POST",
    data,
  };
};

store.dispatch(login({ id: 1, name: "mong", admin: true }));
store.dispatch(addPost({ userId: jyj, id: 1, content: "HI,there." }));
store.dispatch(addPost({ userId: jyj, id: 2, content: "nice" }));
store.dispatch(logout());

{ user:{id: 1, name: "mong", admin: true}, posts:[{ userId: jyj, id: 1, content: "HI,there." },{ userId: jyj, id: 2, content: "nice" } ] }
{user:null, posts:[]}
console.log 순서

//1. 로그인 하기 전
{user:null, posts:[]}
//2. 로그인 후
{ user:{id: 1, name: "mong", admin: true}, posts:[] }
//3. 게시물 1개 올렸을 때
{ user:{id: 1, name: "mong", admin: true}, 
  posts:[{ userId: jyj, id: 1, content: "HI,there." } ] }
//4. 게시물 연속 올렸을 때
{ user:{id: 1, name: "mong", admin: true}, 
  posts:[{ userId: jyj, id: 1, content: "HI,there." },
         { userId: jyj, id: 2, content: "nice" } ] }
//5. 로그아웃
{user:null, posts:[]}

리덕스 흐름: 기본값(state)에서 출발해서, state를 무엇으로 바꿀 것인지 정의해주는 action을 만들고, dispatch함수로 액션을 발생시키고 action을 받아서 reducer가 state를 새로운 객체로 만들어준다.

리덕스를 사용할 때 주의해야 할 규칙

  • 단일 스토어: 하나의 어플리케이션에는 하나의 스토어! 여러 개의 스토어를 사용하는 것이 가능하지만, 상태 관리가 복잡해질 수 있기때문에 권장하지 않는다.
  • 불변성: 리액트에서 state를 직접적으로 건들이지 않는 것과 마찬가지로 리덕스도 마찬가지로 상태를 업데이트할 때 기존의 객체를 건드리지 않고 새로운 객체를 생성한다. -> 객체의 변화를 감지할 때 객체의 깊숙한 안쪽까지 비교하지 않아 좋은 성능을 유지할 수 있는 것이다.
  • 리듀서는 순수함수: 변화를 일으키는 리듀서 함수는 순수함수이다. 파라미터인 이전 상태와 액션 객체 외의 값에는 의존하면 안된다.
    구체적으로 함수 내부에 랜덤 값을 만드는 경우, date함수를 통해 현재 시간을 가져오는 경우, 네트워크 요청하는 경우는 파라미터가 같아도 다른 결과를 만들어낼 수 있기에 사용하면 안된다. -> 액션을 만들 때 처리하거나 리덕스 미들웨어에서 처리하도록 해야한다.

*참고: 리덕스를 사용해야하는지 고민할 때에는 다음의 사항을 고려하면 된다고 한다.

  1. 프로젝트의 규모가 크다면 Redux, 아니라면 context API
  2. 비동기 작업을 자주 한다면 Redux, 아니라면 context API
  3. 리덕스 사용이 편하다면 Redux, 아니라면 context API or Mobx
profile
Lv.1🌷

0개의 댓글