[꼼꼼한 개발자] 꼼코더

[React] - useReducer()란 간단하고 쉽게 이해하기(예제코드, useReducer 사용예제) 본문

간단하고 쉽게

[React] - useReducer()란 간단하고 쉽게 이해하기(예제코드, useReducer 사용예제)

꼼코더 2023. 10. 16. 00:49
반응형
 

🧹 쉬운 정리

1. useReducer()는 useState()와 같은 상태 관리, 상태 업데이트 훅(Hook)이다.

2. 변경할 값이 많을 때(상태 업데이트) 즉 상태 관리할 데이터가 많아질 때 사용을 고민해 볼 필요가 있다.

3. 좀 더 구조화된 방식으로 상태를 관리하고 싶을 때 사용할 수 있다. ( 예) "PLUS" 타입 은 무조건 더하기)

4. 선언형태 : const [state, dispatch] = useReducer(reducer, initialState); 

 

  • state : 상태 이름 (컴포넌트에서 사용할 상태) > 빵(재료) 담는 접시
  • dispatch : 상태(state)를 변경 시 필요한 정보를 전달하는 '함수' > 주문서
  • reducer : dispatch를 확인해서 state를 변경해 주는 '함수' > 주방(공장)
  • initialState : state에 전달할 초기 값 > 빵(및 재료 등) 개수 설정

 



👀 서론

리액트에서 상태 관리(업데이트)를 다루는 훅은 2가지 종류가 있다.

  1. useState()
  2. useReducer() 

useReducer를 처음 봤을 때 어렵게 느껴질 것이다. 하지만 추후에 Redux 이해에도 많은 도움이 되는 개념일 뿐더러
useState만 사용할 수 있는 '선택불가한 개발자'보다는  useState와 useReducer중 '선택가능한 개발자가 되길 바라며

 

그래도 이 글을 읽을 때 중간에 포기하여 나가지 말고

꼭 끝까지 봐줬으면 한다! 개념 익힘, 학습에 정말 도움이 될 거라고 확신한다. 

 

이 글에서는 useReducer()에 대해서 비유와 함께 쉽게 이해할 수 있도록 작성해 보았다! 😀

(추천하진 않지만 정 급하신 분들은 최하단 예제 코드 참고)

 

(참고) useReducer()에 3가지 인자 값 중에서 'init'이라는 3번째 인자 값(함수) 또한 있지만

이번 글에서는 useReducer()의 개념을 간단히 알아가고자 'init(함수)'는 사용하지 않는다.

 

 

 


 

 

💡 useReducer()란?(useState와 차이점)

리액트(React)의 useReducer는 상태 관리와 상태 업데이트를 다루는 React 훅 중 하나.

이 훅은 주로 복잡한 상태 관리 로직을 다루거나 여러 컴포넌트 간에 상태를 공유할 때 사용.

 

useReducer는 클래스 컴포넌트에서의 setState 메서드와 유사한 역할을 하지만

좀 더 구조화된 방식으로 상태를 관리할 수 있도록 도와준다.

 

 

 


 

🧑🏻‍🍳 사용 방법 

먼저 개념부터 안내 후 확인했던 개념들을 코드예제를 통하여 정말 정말 쉽게 알려주겠다!

🏟️ useReducer() 선언과 initialState

useReducer()를 사용하기 위한 초기 선언방식부터 살펴본다! 

const [state, dispatch] = useReducer(reducer, initialState);

state : 상태 이름 (컴포넌트에서 사용할 상태) > 빵 재료 담는 접시

dispatch : 상태(state)를 변경 시 필요한 정보를 전달하는 '함수' > 주문서

reducer : dispatch를 확인해서 state를 변경해 주는 '함수' > 제작

initialState : state에 전달할 초기 값 > 빵 재료

 

 

initialState 초기 값은 객체, 배열 등 다양한 값으로도 전달할 수 있다.

 

 

⭐️ 비유설명

const [state, dispatch] = useReducer(reducer, 3);

 

🙋🏻‍♂️ 빵 제작 요청자 : "음 빵 재료를 '처음에는' 3개로 해야지~ (initialState)" -> "다 골랐으니 접시에 넣어야 겠다!(state)" ->

 

👨🏻‍🍳 주방장 : "다들 주목! 우리 주방은 정해진 '주문서(dispatch)'대로만 '제작(reducer)'한다 알겠나?"

🧑🏻‍🍳 주방원들 : "넵!" 

 

 

여기서 잠깐 dispatch, reducer는 내가 만든 적도 없는데 이거는 죄다 뭐지??

아래에서 먼저 reducer부터 확인해 보자 (dispatch는 3번)

 

 


👨🏻‍🍳 reducer()와 action에 대해서

reducer()는 2가지 인자를 받는다 

  • state : 위에서 선언한 state값 이 들어간다. (초기 값은 당연히 initialState에서 설정한 값)
  • action : 업데이트를 위한 정보를 가지고 있는 '객체' 즉 위에서 선언한 dispatch라고 생각 (주문서)

(그렇다면 action 객체는 어떻게 생겼을까? 추후 아래에서 설명 우선 reducer() 비유 설명부터 보자!)

 

 

⭐️ 비유설명

function reducer(state, action) {
	switch (action.type) {
    	case 'PLUS':
        	return state + 1;
        case 'MINUS': 
        	return state - 1;
        default: return state; 
   }
}

 

 

 

👨🏻‍🍳 주방장 : "우리 주방은 '주문서(dispatch)' 속 주문내역이 'PLUS' 라면 어떠한 재료(state)가 오더라도 무조건 + 1해 알겠어!?

 

🧑🏻‍🍳 주방원들 : "넵!" 

 

👨🏻‍🍳 주방장 : "이것이 내가 적어놓은 제조 방식(reducer)이니 적어놓은 대로만 실행하란 말이야! 알겠어!?"

 

 

(action 객체를 확인해 보자.. 이 부분만 확인하면 끝이다! 좀 만 힘을 내보자)

 

 


 

🥘 action객체(dispatch)

action객체 즉 dispatch는 위에 비유로 설명하자면

'빵 주문자가 주방에 전달할  '주문서'이다.

 

이곳에는 reducer()에 적어놨던 type을(주문 명령어) 적는다.

또한 reducer에서 필요할 데이터, 데이터 값(빵 재료들)도 같이 전달할 수 있다.

 

작성 시 무조건 따라야 하는 규칙은 아니지만 흔히 말하는 '국룰'은

'type 속 액션(값)은 대문자와 '_'로 구성하자'

// 1을 더하는 액션(주문 명령)
{
  type: 'PLUS'
}
// 1을 빼는 액션(주문 명령)
{
  type: 'MINUS'
}
// input 값을(빵 속 재료 등) 변경하는 액션(주문 명령)
{
  type: 'CHANGE_INGREDIENT',
  ingredient : 'corn',
  price : 3000
}
// 새로운 객체(빵)를 생성하는 액션 (주문 명령)
{
  type: 'CREATE_BREAD',
  bread: {
    name: 'corn_bread',
    price: 4500
  },
  ingredient: {
    name: 'corn',
    value: '300g'
  }
}

 

⭐️ 비유설명

dispatch는 말했지만 state를 변경할 수 있는 "명령어"와 정보들을 세팅하는 곳이라고 생각하면 된다.

보통 아래 2가지 형식으로 많이 사용한다.

// 1번째 방법
const onPlus = () => {
   dispatch({type : 'PLUS'})
}

<button onClick={onPlus}>Plus</button>

/// 2번째 방법
<button onClick={() => dispatch({ type: 'PLUS' })}>Plus</button>

🙋🏻‍♂️ 빵 제작 요청자 : "저기 주방장님! 여기 'PLUS' 1회 요청이요!"

 

이제 예제에 적용해서 비유와 함께 쉽게 확인해 보자.

 

 


🧑🏻‍💻 예제 코드

코드를 먼저 읽어보고 

아래에 동작 흐름에 따른 비유도 읽어보면 좋을 듯하다!!

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'PLUS':
      return state + 1;
    case 'MINUS':
      return state - 1;
    default:
      return state;
  }
}

function Baking() {
  // 3을 value 저장
  // 위에 선언했던 값을 변경하는 reducer 함수를 넣어주기!
  // reducer속 로직들을 실행시킬 명령어가 담겨있는 dispatch 선언
  const [value, dispatch] = useReducer(reducer, 3);

  const onPlus = () => {
    dispatch({ type: 'PLUS' });
  };

  const onMinus = () => {
    dispatch({ type: 'MINUS' });
  };

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onPlus}>+1</button>
      <button onClick={onMinus}>-1</button>
    </div>
  );
}

export default Baking;

 

⭐️ 비유 설명 

흐름 : 초기 랜더링 ->  useReducer() 선언 -> '+1' 버튼 클릭

 

👨🏻‍🍳 주방장 : "다들 주목! 우리 주방은 정해진 '주문서("dispatch")'대로만 '제작(reducer)'한다 알겠나?"

🧑🏻‍🍳 주방원들 : "넵!"

 

👨🏻‍🍳 주방장 : "PLUS 요청이 오면 재료를 어떻게 하라고?'

🧑🏻‍🍳 주방원들 : "현재 재료 상태(number)에서 +1 합니다!"

 

🙋🏻‍♂️ 빵 제작 요청자 : "음 빵 재료 밀가루를 '처음에는' 3개로 해야지~ (initialState)" -> "다 골랐으니 접시에 넣어야겠다!(state)"  -> '+1' 버튼을 눌러서 > "PLUS" 주문 요청을 통해서 밀가루를 4개로 만들어달라고 해야겠다! 

 

( [+1] 버튼 클릭)

👨🏻‍🍳 주방장 : "다들 주목! 방금 dispatch를 통해서 action을 취해달라고 요청이 왔어 여기 손님은.. 어디 보자.. type은..'PLUS'네? 그리고 밀가루를 3개를 같이 보내주었네..? 에헤이 이전 손님은 옥수수여서 편했는데.. 아무튼 우리는 PLUS 요청이 오면 재료를 어떻게 하라고?'


🧑🏻‍🍳 
주방원들 : "넘어온 재료를 (number)  +1 합니다!"

👨🏻‍🍳 주방장 : "뭐 해 당장 진행시켜!(reducer 속 case 실행)

 

 


 

🙋🏻‍♂️ 마무리

제 설명이 잘 전달이 됐을지 모르겠네요..

저도 최근에 공부한 초보자라.. 습득한 지식이라 잘못된 지식이 있다면 지적 매우 환영합니다!

 

추후 초기 값을 객체를 넣고 reducer에서 spread 방식을 사용하여 값을 저장하는 방식을 사용하다 보면 어려워질 수 있어 보입니다!

따라서 useState(), useReducer() 등을 각 상황에 맞게 잘 사용해 보는 고민도 해보시면 좋을 듯합니다!


많은 도움이 되셨길 바라며 그럼 이만!

 




참고 : https://react.vlpt.us/basic/20-useReducer.html

Comments