본문 바로가기

Programming/React

[React] React Hooks : 6. useReducer

 

1. useReducer 란?

useState와 비슷하게 상태를 관리/수정할 때 사용하는 훅이며, Context API, useContext 와 같이 사용되는 경우가 많다.

// useState
const [state, setState] = useState();
// 상태, 상태변환

// useReducer
useReducer(reducer, initialState);
// 상태변환, 상태

 

1) useState와의 차이점

useReducer는 더 복잡한 로직의 상태를 관리하는데 사용되는 경우가 많다.

 

2) useReducer를 언제 사용해야 하는가?

2-1) useState보다 더 복잡한 로직 상태 관리가 필요할 때

2-2) Redux 사용시

 

 

2. useReducer 사용하기

dispatch가 reducer로 action과 state를 보내고, reducer가 이것을 받아서 initialState에 영향을 준다.

dispatch -(action, state)→ reducer -(action, state)→ initialState

 

ex) useReducer를 통해 number값 증가,감소,리셋하기

// 1. 최상단에서 useReducer Hook 호출
import { useReducer } from 'react';

// 2. initialState 값 최초 설정
const initialState = 0;

// 3. reducer 함수 작성(동작 유형에 따라 switch 문을 통해 case로 정의) 
const reducer(state, action) {
  switch (action.type) {
    case "increment": // 증가 action
      return state + 1;
    case "decrement": // 감소 action
      return state - 1;
    case "reset": // 초기화 action
      return 0;
    default:
      throw new Error();
  }
}

const App() {
  // 4. 컴포넌트 내에서 useReducer Hook 초기화
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h1> Count: {state}</h1>
       <!-- 5. 각각의 필요한 action.type의 dispatch 추가 -->
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
    </div>
  );
}

 

1) 최상단에서 useReducer Hook 호출

import { useReducer } from 'react';

 

2) initialState 값 최초 설정

const initialState = 0;

 

3) reducer 함수

state와 action을 받아 값을 return하는 함수.

(동작 유형에 따라 switch 문을 통해 case로 정의) 

const reducer(state, action) {
	return state + action;
}
const reducer(state, action) {
  switch (action.type) {
    case "increment": // 증가 action
      return state + 1;
    case "decrement": // 감소 action
      return state - 1;
    case "reset": // 초기화 action
      return 0;
    default:
      throw new Error();
  }
}

위와 같은 reducer 함수 선언으로 상태를 최신화한다.

action은 state의 값이 어떻게 바뀔지를 결정하며, 달라진 state 값은 최초의 state와 action에 영향을 준다.

 

4) 컴포넌트 내에서 useReducer Hook 초기화 연결

const App() {
  // 컴포넌트 내에서 useReducer Hook 초기화
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <h1> Count: {state}</h1> // state 값 불러오기
    </div>
  );
}

 

5) dispatch 함수

action은 dispatch 함수를 통해 전달되어 state의 값을 최신화 한다.

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

  return (
    <div>
      <h1> Count: {state}</h1>
       <!-- 각각의 필요한 action.type의 dispatch 추가 -->
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
    </div>
  );
}

 

 

Redux 사용 시 dispatch 함수는 하단의 형식으로 객체를 전달한다.

{type: 'Add', payload: 1}

type은 action에 대한 설명이고, payload는 state value 값을 말한다.

 

 

3. useReducer 사용시 숙지 사항

 

1) Redux에는 중앙 저장소인 'store' 가 있어 데이터를 모든 컴포넌트에서 접근할 수 있다.

useReducer 자체에는 이러한 것이 없어 컴포넌트 내에서만 로컬로 데이터를 저장한다.

 

2) reducer() 함수는 순수한 함수로 작성되어야 한다.

만약 같은 argument가 전달되고 side effects가 없다면 함수는 무조건 같은 값을 리턴한다.

 

3) initialState의 초기화

useReducer는 선택적으로 3번째 argument인init(initialArg)를 가질 수 있는데,

init은 initialState와 함께 저장하는 함수다.

 

ex) init function 사용 예시

// 1. 최상단에서 useReducer Hook 호출
import { useReducer } from 'react';

// 2. init 사용시 아래와 같이 initialState 값 최초 설정
const init(initialState){
  return initialState;
}

// 3. reducer 함수 작성(동작 유형에 따라 switch 문을 통해 case로 정의) 
const reducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return state + 1;
    case "decrement":
      return state - 1;
    case "reset":
      return init(action.payload);
    default:
      return;
  }
}

const App = () => {
  // 4. 컴포넌트 내에서 useReducer Hook 초기화시 3번째 argument로 init을 추가해준다.
  const [state, dispatch] = useReducer(reducer, initialState, init);

  return (
    <div>
      <h1> Count: {state}</h1>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <!-- 5. 각각의 필요한 action.type의 dispatch 추가시 payload:initialState로 추가 -->
      <button onClick={() => 
        dispatch({ type: "reset", payload: initialState})}>Reset</button>
    </div>
  );
}