WEB/React

Hooks - useReducer

Harimad 2022. 4. 14. 23:05

정의

useReducer는 useState보다 더욱 다양한 컴포넌트 상황에 따라
다양한 상태를 다른 값으로 업데이트 해주고 싶을 때 사용하는 Hook이다.

reducer는 현재 상태, 그리고 업데이트를 위해서 

필요한 정보를 담은 액션(action)값을 전달받아 새로운 상태를 반환하는 함수이다.
reducer 함수에서 새로운 상태를 만들 때는 반드시 불변성을 지켜야 한다.

function reducer(state, action) {
  return { ... };  // 불변성을 지키면서 업데이트한 새로운 상태를 반환한다.
}

액션 값은 주로 다음과 같은 형태로 이루어져 있다.

{ 
  type: 'INCREMENT',
  // 다른 값들이 필요하다면 추가로 들어감
}

카운터 구현하기

먼저 useReducer를 사용해서 기존의 Counter를 다시 구현해 본다.

import React, { useReducer } from 'react';

function reducer(state, action) {
  // action.type에 따라 다른 작업 수행
  switch (action.type) {
    case 'INCREMENT':
      return { value : state.value + 1 };
    case 'INCREMENT':
      return { value : state.value - 1 };
    default:
      // 아무것도 해당되지 않을 때 기존 상태 반환
      return state;
  }
}
const Counter = () => {
  const [state, dispatch] =useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        현재 카운터 값은 <b>{state.value}</b>입니다.
      </p>
      <button onClick={() => dispatch( { type: 'INCREMENT' } )}>+1</button>
      <button onClick={() => dispatch( { type: 'DECREMENT' } )}>-1</button>
    </div>
  )
}

export default Counter;

useReducer의 첫 번째 인자에는 reducer 함수를 넣고, 두 번째 인자에는 해당 reducer의 기본값을 넣는다.
이 Hook을 사용하면 state값과 dispatch 함수를 받아온다.
여기서 state는 현재 가리키고 있는 상태이고, dispatch는 액션을 발생시키는 함수이다.
dispatch(action)과 가은 형태로, 함수 안에 인자로 액션 값을 넣어 주면 reducer 함수가 호출 되는 구조이다.

 

useReducer를 사용할 때 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 밖으로 뺄 수 있다는 것이다.

 

인풋 상태 관리하기

useReducer를 이용해서 Info 컴포넌트에서 인풋 상태를 관리해 본다.
기존에는 인풋이 여러 개라서 useState를 여러 번 사용했다.
useReducer를 사용하면 기존에 클래스 컴포넌트에서 input 태그에 name 값을 할당하고
e.target.name을 참조하여 setState를 해준 것과 유사한 방식으로 작업처리를 할 수 있다.

//Info.js
import React, { useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.name]: aciton.value
  }
}

const Info = () => {
  const [state, dispatch] useReducer( reducer, {
    name: '',
    nickname: ''
  });
  const { name, nickname } =state;
  const onChange = e => {
    dispatch(e.target);
  };
  return (
    <div> 
      <div>
        <input name="name" value={name} onChange={onChange} />
        <input name="nickname" value={nickname} onChange={onChange} />
      </div>
      <div>
        <div>
          <b>이름:</b> {name}
        </div>
       </div>
    </div>
  );
};
export default Info;

useReducer에서 액션은 그 어떤 값도 사용 가능하다.
그래서 이번에는 이벤트 객체가 지니고 있는 e.target 값 자체를 액션 값으로 사용했다.
이런 식으로 인풋을 관리하면 아무리 인풋 개수가 많아져도 코드를 짧고 깔끔하게 유지 할 수 있다.

 


 

출처

리액트를 다루는 기술  - 김민준
(8장 Hooks, 17장 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기)


참조

useReducer 를 사용하여 상태 업데이트 로직 분리하기

devdocs - react - useReducer