[TIL # 61] React Basic (6)

Yejin Yang·2022년 8월 10일
0

[TIL]

목록 보기
60/67
post-thumbnail

[수업 목표]

  1. Redux 에 대해서 이해한다.
  2. Redux 로 Todo List 를 만들어본다.

⭐️ 새롭게 안 사실

Redux 란?

리덕스는 리액트에서 가장 많이 사용되는 상태 관리 라이브러리중 하나이다. 리덕스를 사용하면 컴포넌트의 상태 업데이트 관련 로직을 다른 파일로 분리시켜서 효율적으로 관리할 수 있다. 최근 Redux Toolkit이 등장하면서 더욱 더 이 효율성은 빛을 보이고 있다.

이전에 useReducer 를 썼을 때와 비슷한 구조를 가지고 있다. +1 버튼을 누르면 수가 증가하고, -1 버튼을 누르면 수가 감소하는 카운터를 구현한다고 생각해보자.

Action Type 정의
어떤 action 이 있으면 좋을지 생각해서 정의 해놓는다.

export const INC_COUNT = "INC_COUNT";
export const DEC_COUNT = "DEC_COUNT";

변수 형태로 미리 만들어놓는 이유

  1. export 를 해서 다른 파일에서 편하게 불러와서 사용할 수 있도록 하기 위함
  2. 혹시나 있을 오타 등을 방지하기 위한 의도

Action 생성 함수
원칙적으로 항상 액션 객체를 리턴해야 한다!

{ type: INC_COUNT, payload: ~~ } 와 같은 객체를 redux 에서는 action 객체라고 말한다.

이러한 action 객체를 reducer 로 보내는 행위를 dispatch 라고 표현한다.

dispatch 에 action 객체를 직접 명시해서 전달하기도 하지만, dispatch 에 action 객체를 Return 하는 함수를 전달해서 사용하는 경우도 있다.

이렇게 action 객체를 return 하는 함수를 action 생성 함수라고 표현한다.

export function incCount(diff) {
    return {
        type: INC_COUNT,
        payload: {diff},
    }
}

export function decCount(diff) {
    return {
        type: DEC_COUNT,
        payload: {diff},
    }
}

ex) 만약 버튼을 눌렀을 때 수가 2씩 증가하도록 하는 action 객체를 생성해서 reducer 로 보내고싶다면? → dispatch(incCount(2)) 라고 실행한다.

Reducer

state 는 불변성을 유지해야 한다. 동일한 파라미터가 들어왔다면 동일한 결과를 출력해야 한다. (date 등을 사용할 경우 해당 부분은 액션 생성 시 처리하고, 리듀서에서 그러한 랜덤 로직을 사용해서는 안됨)

function counter(state = initialState, action) {
    switch (action.type) {
      case INC_COUNT:
        return state + 1
      case DEC_COUNT:
        return state - 1;
      default:
        return state;
    }
  }

Store

store 란 앞서 만든 리듀서와 상태를 담아놓은 것이다. 이 storeProvider 라는 것을 통해서 컴포넌트에 공유함으로써, 어떤 컴포넌트에서든 리듀서와 상태를 가져와서 사용할 수 있도록 코드를 작성한다.

import { legacy_createStore as createStore } from "redux";
import counter from "./reducers/counter";

const store = createStore(counter);

export default store;

useSelector

useSelector 는 redux 로 관리 중인 상태를 가져오기 위한 Hook이다.

state 안에 number 라는 데이터가 있다면, 아래처럼 가져올 수 있다. dispatch 를 통해서 state 가 변하게 되면, 자동으로 useSelector 를 통해서 받아온 state 도 변하게 된다.

import { useSelector } from 'react-redux'

const { number } = useSelector(state => state)

useDispatch

useDispatch 는 dispatch 함수를 실행할 수 있도록 해주는 Hook 이다. 만들어진 액션 객체를 Reducer 로 전달하는 과정을 수행해주는 Hook 이라고 생각하면 된다.

import { useDispatch } from 'react-redux'

const dispatch = useDispatch()

// 사용 예시
dispatch(incCount(1))

📌 꼭 기억할 것

Store 하나의 앱에는 하나의 스토어가 있도록 구성하는 것이 규칙이다.

createStore

import { legacy_createStore as createStore } from "redux";
import counter from "./reducers/counter";

const store = createStore(counter);

export default store;

legacy_createStore 가 아닌 그냥 createStore 의 경우 deprecate 되었다고 한다. redux 개발자들이 redux toolkit 사용을 권장하기 위해서 해당 함수를 deprecate 시켰으나, 사용 빈도를 보면 createStore 를 쓰는 경우도 아직 많은 것으로 보인다.

ducks 패턴


기존패턴은 이렇게 폴더를 나누어서 코드를 작성하는 방법이다.

하지만 ducks 패턴은 하나의 파일에다가 모든 코드를 작성하는 것을 말한다. 코드 작성이 조금 더 용이해지고, 폴더 구조 상의 가독성이 더 좋아진다는 장점이 있다.

[규칙]

  1. 반드시 리듀서 함수를 default export 해야 한다.
  2. 반드시 액션 생성 함수를 export 해야 한다.
  3. 반드시 접두사를 붙인 형태로 액션타입을 정의해야 한다.
  4. (선택) 액션 타입은 UPPER_SNAKE_CASE 형태로 이름을 짓고 export 할 수 있다.
// 액션 타입
const INC_COUNT = "counter/INC_COUNT";
const DEC_COUNT = "counter/DEC_COUNt";

// 액션 생성 함수
export function incCount(diff) {
    return {
        type: INC_COUNT,
        payload: {diff},
    }
}

export function decCount(diff) {
    return {
        type: DEC_COUNT,
        payload: {diff},
    }
}

// 초기값
const initialState = {number: 0};


// 리듀서 선언
export default function counter(state = initialState, action) {
    switch (action.type) {
      case INC_COUNT:
        return {
          ...state,
          number: state.number + action.payload.diff
        }
      case DEC_COUNT:
        return {
          ...state,
          number: state.number - action.payload.diff
        };
      default:
        return state;
    }
  }
profile
Frontend developer

0개의 댓글