TIL 75일차

Moon Seongseok·2021년 4월 26일
0

Redux

목록 보기
1/2

⛱ TypeScript 환경에서 Redux 사용법

벨로퍼트님 벨로그를 참고하여 작성하였습니다.


리덕스를 적용한 리액트 프로젝트 만드는 커맨드

$ npx create-react-app ts-react-redux-tutorial --typescript
$ cd ts-react-redux-tutorial
$ npm install redux react-redux @types/react-redux

redux의 경우엔 자체적으로 TypeScript 지원이 된다. 하지만 react-redux의 경우 그렇지 않기 때문에 패키지명 앞에 @types를 붙인 패키지를 설치해야한다.

코드 작성 순서

1. 리덕스 모듈 작성

Ducks 패턴을 사용하여 한 파일에 액션의 Type, 액션 생성함수, 리듀서를 작성

아래는 모듈 작성 순서

1. 액션 type 선언 (리덕스 액션 안에 들어가게 될 type 선언)

2. 액션 생성 함수 선언

3. 액션 객체들에 대한 type 준비하기(Typescript의 type)

4. 상태의 타입과 상태의 초기값 선언하기

5. 리듀서 작성하기

2. 커스텀 hook 작성

3. 작성한 hook을 이용하여 state와 함수들 사용

커스텀 hook을 이용하는 이유는 기존 방식과 다르게 좀 더 간결하게 코드를 작성할 수 있다는 장점이 있어서이다.

설명 추가 예정


위 순서에 맞게 작성한 코드


modules/counter.ts

//액션 타입 선언
const INCREASE = "counter/INCREASE" as const;
const DECREASE = "counter/DECREASE" as const;
const INCREASE_BY = "counter/INCREASE_BY" as const;

as constconst assertions라는 타입스크립트 문법이다.
as const를 사용함으로써, 나중에 액션 생성함수를 통해 액션 객체를 만들 때 typescript 타입이 string이 되지 않고 실제 값이 된다. 
위에 코드에서 실제값은 "counter/INCREASE" ...

//액션 생성 함수
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
export const increaseBy = (diff: number) => ({
  type: INCREASE_BY,
  payload: diff,
});

//액션 객체들에 대한 type 준비하기
type CounterAction = 
  | ReturnType<typeof increase> 
  | ReturnType<typeof decrease> 
  | ReturnType<typeof increaseBy>;

나중에 리듀서 작성할 때 action 파라미터의 ㅏ입을 설정하기 위한 코드

//상태에 관한 type과 상태 생성 코드
type CounterState = {
  count: number;
};

const initialState: CounterState = {
  count: 0,
};

//reducer 함수
function counter(state: CounterState = initialState, action: CounterAction) {
    switch (action.type) {
      case INCREASE:
        return { count: state.count + 1 };
      case DECREASE:
        return { count: state.count - 1 };
      case INCREASE_BY:
        return { count: state.count + action.payload };
      default:
        return state;
    }
  }
  
  export default counter;

------------------------------------------------------------------------

modules/index.ts

import { combineReducers } from 'redux';
import counter from './counter';

const rootReducer = combineReducers({
  counter
});

export default rootReducer;

export type RootState = ReturnType<typeof rootReducer>;

-------------------------------------------------------------------------
hooks/useCounter.tsx 

import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../modules';
import { increase, decrease, increaseBy } from '../modules/counter';
import { useCallback } from 'react';

export default function useCounter() {
  const count = useSelector((state: RootState) => state.counter.count);
  const dispatch = useDispatch();

  const onIncrease = useCallback(() => dispatch(increase()), [dispatch]);
  const onDecrease = useCallback(() => dispatch(decrease()), [dispatch]);
  const onIncreaseBy = useCallback(
    (diff: number) => dispatch(increaseBy(diff)),
    [dispatch]
  );

  return {
    count,
    onIncrease,
    onDecrease,
    onIncreaseBy
  };
}
---------------------------------------------------------------------
  
  components/Counter.tsx

import React from 'react';
import useCounter from '../hooks/useCounter';

function Counter() {
  const { count, onIncrease, onDecrease, onIncreaseBy } = useCounter();

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
      <button onClick={() => onIncreaseBy(5)}>+5</button>
    </div>
  );
}

export default Counter;

0개의 댓글