useReducer 사용

미마모코딩·2022년 10월 7일
0

리액트 기본기

목록 보기
4/6
post-thumbnail

react에서는 useState hook을 이용해 상태를 관리한다.

useReducer는 useState hook을 대체 할 수 있는 react hook이다.

그렇다면 useState로 관리하면 되는데 왜 useReducer가 등장했을까?

useReducer는 한 컴포넌트 내에서 State를 업데이트하는 로직 부분을
기존 컴포넌트로부터 분리시키는 것을 가능하게 해준다는 것이다.

useReducer는 이런 형식으로 사용된다

const [state, dispatch] = useReducer(reducer, initialState, init);
스테이트 , 디스패치 ,리듀서 ,이니셜스테이트는 전부 아래서 다룰 예정이다.

즉 State 업데이트 로직을 또다른 파일에 작성해 (분리), 분리된 파일을 import해 사용하는 것이 가능하다.

그러면 상태관리를 하는 hook이 두개인데 어느 순간에 useState를 , 어느순간에 useReducer를 써야할까?

useState를 권장하는 순간 -
관리해야 할 State가 1개일 경우
관리하는 State가 단순한 숫자, 문자열 또는 Boolean 값일 경우

useReducer를 권장하는 순간-
관리해야 할 State가 1개 이상, 복수일 경우
현재는 단일 State 값만 관리하지만, 추후 유동적일 가능성이 있는 경우
스케일이 큰 프로젝트의 state의 구조가 복잡해질경우

위 배경지식들을 이해하고 받아들이며 useReducer를 공부해보자.

먼저 useReducer를 이해하기에 앞서 action , reducer,, dispatch , payload를 공부해보자

action란?

Action은 상태 변경을 일으키는 이벤트에 대한 정적인 정보이다. Reducer가 Action과 이전 state을 참고해서 새로운 state를 만들기 때문에 Action은 reducer가 구분 할 수 있도록 액션의 이름(타입) 과 데이터를 가진 객체형식이다.

export const ACTION_TYPE = {
  FETCH_START: "FETCH_START",
  FETCH_SUCCESS: "FETCH_SUCCESS",
  FETCH_ERROR: "FETCH_ERROR",
};
 
 위와 같이 객체안에 몰아넣는 방법과 
 
export const FETCH_START = "FETCH_START" 이런식으로 작성하는 방법이 있다.

당장은 이해하지 못해도 괜찮다 이런게 있구나 정도로만 따라와도 충분하다.

redux,useReducer는 동작이 상당히 비슷하다

상태를 바꾸는데 있어서 액션은 정말 특정한 액션이라는거다

state과 바뀌는 것을 현실세계의 옷을 구매하는것이라고 생각해보자.

1.옷을산다라는 액션이 필요함
2.옷을 산다라는 액션이 실행되면 내 계좌(state)에서 -금액이 발동되어야한다.
3.그래서 swich문으로 case가 옷을산다 일때? state의 값을 변동해 리턴해주는것이다.

reducer란?

reducer 함수는 dispatch 함수에 의해 실행되며, 컴포넌트 외부에서 state를 업데이트하는 로직을 담당한다.
reducer 함수는 현재의 state와 action을 인자로 받게 된다.
이 action의 타입에 근거하여 기존의 state를 복제하여 새로운 state를 반환한다.

export const INITIAL_STATE = {
  loading: false,
  post: {},
  error: false,
}; //state의 초기값 이니셜라이징 
                               스테이트변수 초기화      액션객체
export const postReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "FETCH_START":
      return {
        loading: true,
        post: {},
        error: false,
      };
    case "FETCH_SUCCESS":
      return {
        ...state,
        loading: false,
        post: action.payload,
      };
    case "FETCH_ERROR":
      return {
        loading: false,
        post: {},
        error: true,
      };

    default:
      return state;
  }
};

위코드를 다시 옷사는 과정이라고 보면 이렇게 해석 할 수 있다.

1.내 통장의 초기화된 일정 금액이있다.

이 돈을 쓰기 위해선 땅에 버리든지 , 옷을 사든지 , 밥을 먹든지 특정한 행동이 있을 때 내가 가진 돈이 줄어든다 . < 이게 액션이다.
버린다 , 산다 ,먹는다 , 이런 행동이 액션의 타입이다.

우리는 미리 스위치문을 통해 케이스를 정해놓는 것이다.
옷을산다라는 액션타입이 들어오면 내가 가진 옷의 수 + 1 ,내가 가진 초기금액 - 옷 금액
이렇게 state의 상태를 관리하는 것이다.

이때 알아야 하는게 dispatch다.

dispatch란?

dispatch 함수는 reducer 함수를 실행시킨다.
dispatch 함수의 인자로써 업데이트를 위한 정보를 가진 action를 이용하여,
컴포넌트 내에서 state의 업데이트를 일으키기 위해서 사용된다.

import React, { useReducer } from "react";
import { INITIAL_STATE } from "./postReducer";
import { postReducer } from "./postReducer";
import { ACTION_TYPE } from "./PostActionTypes";

const App = () => {
  const [state, dispatch] = useReducer(postReducer, INITIAL_STATE);
  const handleFetch = () => {
    dispatch({ type: ACTION_TYPE.FETCH_START });
    fetch("https://jsonplaceholder.typicode.com/posts/1")
      .then((res) => {
        return res.json();
      })
      .then((data) =>
        dispatch({ type: ACTION_TYPE.FETCH_SUCCESS, payload: data })
      )
      .catch((err) => dispatch({ type: ACTION_TYPE.FETCH_ERROR }));
  };
  return (
    <div>
      <button onClick={handleFetch}>{state.loading ? "Wait !" : "go!"}</button>
      <p>{state.post?.title}</p>
      <span>{state.error && "SOMETHING wrong"}</span>
    </div>
  );
};

export default App;

디스패치는 이처럼 객체안에 액션의타입을 아래와 같이 지정한다.

ex) dispatch({ type: ACTION_TYPE.FETCH_START });

payload

페이로드는 우리가 리듀서로 전달해주는 모든 데이터가 페이로드이다.

위 코드는 데이터를 패칭하는과정인데

dispatch({ type: ACTION_TYPE.FETCH_SUCCESS, payload: data })
이렇게 디스패치안에 페이로드로 무언가 데이터를 담아서 보내면
리듀서에서 payload를 받아 상태를 업데이트 하는 개념이다.

정말 중요하고 redux의 진입장벽을 낮출 가이드이니 여러번 보고 이해하고 코드를 작성해보면 좋겠다.

0개의 댓글