본문 바로가기
JS/React 강의

[React] 14. useReducer() 사용법 총정리

by 박기린 2023. 11. 21.

 

안녕하세요. 박기린 입니다.

이번엔 React Hooks 중 하나인 useReducer()에 대해 알아보겠습니다.

 

 


useReducer 란 무엇일까?

간단하게 설명하자면, useState()처럼 state를 수정하는 React Hook 함수입니다. 그래서 일반적으로 useState()를 사용하기에, useReducer()를 자주 사용하진 않습니다만, 특수한 경우에 useReducer()가 도움이 될 수 있습니다.

 

 

도움이 되는 경우

  • state가 엄청 많은 경우
  • state를 조작하는 수단이 너무 많은 경우
  • 어떤 state가 다른 state로부터 종속된 부분이 많은 경우

위의 경우 useState()를 사용하면 어려움이 있거나 에러가 발생할 수 있습니다. 이때 대체제로 useReducer()를 사용할 수 있습니다.

 

 

 

 


useReducer() 사용법

const [ state, dispatch함수 ] = useRedcuer( reducer함수, 초기state, 초기함수 )

 

useState() - [state, setState ] - 처럼,

useRedcuer()도 항상 두 개의 값이 있는 배열 - [state, dispatch함수] - 을 반환합니다. 그래서 배열 비구조화를 사용합니다.

 

 

반환되는 두 가지 값은 state와 dispatch 함수입니다.

  • state : 최신 state 스냅샷
  • dispatch함수 : 최신 state 스냅샷을 업데이트(값을 수정)할 수 있게 해주는 함수이다. (useState()에서 setState()함수와 비슷한 역할)

 

userReducer() 함수는 3개의 인수를 받습니다.

  • reducer함수 : dispatch함수가 작동하는 방식을 정의한다. 
  • 초기state : 말 그대로 State의 초기 설정값을 정의한다.
  • 초기함수 : 초기state를 설정하기 위해 실행해야 하는 함수이다. 예를 들어, http 리퀘스트를 받은 후에 초기 state를 설정해야 하는 상황일 때 유용하다)

 

 

 

 


useReducer() 사용 예시

예제 : 이메일 주소(String)와 이메일 유효성(Boolean) states를 하나의 email state로 결합한 후 useRedcuer로 관리하기

 

 

import React, { useReducer } from "react";

React에서 useReducer()를 임포트합니다.

 

 

  const [email, dispatchEmail] = useReducer(emailReducer, {
    value: "",
    isValid: null,
  });

초기 state에는 원하는 초기값을 넣어줍니다. 우리가 원하는 것은 이메일 주소와 유효성 여부를 담는 것이기 때문에, 객체 형태로 state를 설정합니다.

 

 

 

// emailReducer : Reducer 함수
const emailReducer = (state, action) => {
  if (action.type === "USER_INPUT") {
    // 사용자 value를 입력하면
    return { value: action.val, isValid: action.val.includes("@") };
  }
  if (action.type === "INPUT_BLUR") {
    // 사용자가 입력을 끝내면 (인풋 포커스를 잃으면)
    return { value: state.value, isValid: state.value.includes("@") }; // 이 경우에는 action의 type이외에 페이로드 payload property를 받지 않기 때문에, state를 이용한 기존의 최신 state 스냅샷을 가져와서 사용한다.
  }
  return { value: "", isValid: false };
};

Reducer 함수는 리액트 컴포넌트 함수 내부에서 만들어진 어떤 데이터도 필요로 하지 않기 때문에, 컴포넌트 함수 밖에서 선언할 수 있습니다.

 

Redcuer 함수는 두 개의 인수를 받습니다.

  • state : 최신 state 스냅샷
  • action : dispatch된 액션

그리고 새로운 state 스냅샷을 return 합니다.

 

 

 

 

dispatch 함수를 사용해보자

reducer함수까지 만들었으니, 이제 dispatch 함수를 사용할 수 있게 됐습니다.

  1. dispatch 함수는 action 객체를 reducer 함수로 전달하는 역할을 한다.
  2. action 객체는 type property와 payload property를 가질 수 있다.
  3. type property는 관용적으로 "영어_대문자"를 사용해서 액션 이름을 전달한다.
  4. payload property는 관용적으로 val 이라는 프로퍼티 이름을 지정해서 사용한다.
  5. type property에 따라 리듀서 함수가 어떤 방식으로 작동할 지를 지정할 수 있다.

 

 

 

이제 컴포넌트 함수 내부에, dispatch 함수를 사용하기 위한 핸들러 함수를 구현합니다.

  const emailChangeHandler = (event) => {
    dispatchEmail({ type: "USER_INPUT", val: event.target.value });
  };

이메일 입력창에서 사용자로부터 어떤 입력을 받을 때마다, 위 핸들러 함수가 실행됩니다.

dispatch 함수에는 아래의 프로퍼티로 구성된 객체를 전달합니다. (이 객체를 action 객체라고 부릅니다.)

  • type 프로퍼티 : reducer 함수에 USER_INPUT 액션을 disaptch 한다.
  • val 프로퍼티 : reducer 함수에 입력받은 값을 전달한다.

 

 

 

  const validateEmailHandler = () => {
    dispatchEmail({ type: "INPUT_BLUR" });
  };

사용자가 입력을 마치고 이메일 입력창 밖으로 나갈 때, 위 핸들러 함수가 실행됩니다.

dispatch 함수에는 객체를 전달합니다.

  • type 프로퍼티 : reducer 함수에 USER_INPUT 액션을 disaptch 한다.

 

 

 

          <input
            type="email"
            id="email"
            value={email.value}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />

실제 React의 input 컴포넌트에 핸들러함수를 적용시킨 코드는 위와 같습니다.

위 input 컴포넌트에 연결된 핸들러함수들은 이러한 방식으로 작동합니다.

emailChangeHandler는 사용자가 이메일 입력창에 값을 입력할 때마다 작동한다.
dispatchEmail에 ‘USER_INPUT’타입을 지정해주고, payload(val)로 현재 입력값을 넘겨준다. reducer 함수는 if문으로 USER_INPUT 타입의 액션에 걸맞은 행동을 취한다. 입력받은 payload(val)를 email state에 적용한다.


validateEmailHandler는 사용자가 이메일 입력창에서 포커스를 잃을 때마다 작동한다.
dispatchEmail에 ‘INPUT_BLUR’타입을 지정해주고, payload(val)는 넘기지 않는다. reducer 함수는 If 문으로 INPUT_BLUR 타입의 액션에 걸맞은 행동을 취한다. state의 최신 상태를 불러온 후 유효성 검사만 진행한다.

 

 

 


State 관리 - useState vs useReducer

useState

  • 주요 state 관리 툴
  • 간단하면서 적은 수의 개별 state 및 데이터들을 다루기에 적합
  • state의 업데이트가 쉽다
  • 따라서 state가 변경되는 경우가 다양하지 않다면, 특히 객체 형태의 state나 그 비슷한 게 없다면 사용하기 적합.

 

useReducer

  • 더 강력한 state관리 툴을 필요로 할 때 - 객체 형태와 같은 복잡한 state
  • 복잡한 state 업데이트 로직을 포함한 리듀서 함수가 필요하면 - action에 따라 다양한 업데이트 방식을 필요로 하는 경우 or http 리퀘스트를 요구하는 것처럼 업데이트 방식이 더 복잡한 경우
  • 여러 state들로 구성된 데이터를 다루는 경우 (위에서 예시로 사용한 email object state = 이메일 string + 이메일 유효성 bool)

 

 

 

// useState
  const [enteredEmail, setEnteredEmail] = useState("");
  const [emailIsValid, setEmailIsValid] = useState();


// useReducer
  const [email, dispatchEmail] = useReducer(emailReducer, {
    value: "",
    isValid: null,
  });

useRedcuer는 여러 state를 하나의 객체 state로 몰아서 저장하고, reducer 함수를 이용해서 복잡한 업데이트 방식을 간단하게 만들어줍니다.

반응형