front_end/react

React - useReducer (in typescript)

joepasss 2022. 5. 13. 22:38

USEREDUCER


 useState가 여의치 못한 상황일 때 사용 (state 종류가 많던지 등의)

reducer 함수 예시

function reducer(state: CounterState, action: CounterAction) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + action.payload };
    case 'DECREMENT':
      return { count: state.count - action.payload };
    default:
      return state;
  }
}

사용 예시

import { FC, useReducer } from 'react';

type CounterState = {
  count: number;
};

type CounterAction = {
  type: string;
  payload: number;
};

const initialState = { count: 0 };

function reducer(state: CounterState, action: CounterAction) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + action.payload };
    case 'DECREMENT':
      return { count: state.count - action.payload };
    default:
      return state;
  }
}

export const Counter: FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div className='container'>
      Count: {state.count}
      <button
        onClick={() => dispatch({ type: 'INCREMENT', payload: 10 })}
      >
        Increment 10
      </button>
      <button
        onClick={() => dispatch({ type: 'DECREMENT', payload: 10 })}
      >
        DECREMENT 10
      </button>
    </div>
  );
};
  • dispatch를 통해 상태를 변화시킨다

strict action type


  • Reset 추가
function reducer(state: CounterState, action: CounterAction) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + action.payload };
    case 'DECREMENT':
      return { count: state.count - action.payload };
    case 'RESET':
      return initalState;
    default:
      return state;
  }
}

payload 인수 에러

  • payload가 인수로 전달되지 않아 오류가 발생하는 모습이다.

 해결

  • type을 두 가지로 나눈다 (UpdateAction, ResetAction)
type UpdateAction = {
    type: string;
  payload: number;
}

type ResetAction = {
  type: string;
}
  • CounterAction의 타입을 UpdateAction | ResetAction; 으로 둘 다 가능하도록 유니온 시킨다
type CounterAction = UpdateAction | ResetAction;

ResetAction 내부에 payload 인수가 없다는 에러

  • ResetAction type(CounterAction 안에 포함됨)에 payload 인수가 없다는 에러가 뜬다
  • UpdateAction, ResetAction 내부의 type property를 string 이 아닌 INCREMENT, DECREMENT, RESET 등으로 명시 해 준다
type UpdateAction = {
    type: 'INCREMENT' | 'DECREMENT';
  payload: number;
}

type ResetAction = {
  type: 'RESET';
}
  • 에러가 해결된 모습을 볼 수 있다

전체 코드

import { FC, useReducer } from 'react';

type CounterState = {
  count: number;
};

type UpdateAction = {
  type: 'INCREMENT' | 'DECREMENT';
  payload: number;
};

type ResetAction = {
  type: 'RESET';
};

type CounterAction = UpdateAction | ResetAction;

const initialState = { count: 0 };

function reducer(state: CounterState, action: CounterAction) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + action.payload };
    case 'DECREMENT':
      return { count: state.count - action.payload };
    case 'RESET':
      return initialState;
    default:
      return state;
  }
}

export const App: FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div className='App'>
      Count: {state.count}
      <button
        onClick={() => dispatch({ type: 'INCREMENT', payload: 10 })}
      >
        Increment 10
      </button>
      <button
        onClick={() => dispatch({ type: 'DECREMENT', payload: 10 })}
      >
        DECREMENT 10
      </button>
      <button 
        onClick={() => dispatch({ type: 'RESET' })}
      >
        RESET
      </button>
    </div>
  );
};