useReducer Hook

박종한·2020년 2월 3일
0

React

목록 보기
4/17

useReducer Hook?

상태 업데이트에 주로 썼던 useState 뿐만 아니라 useReducer로도 업데이트 가능

차이점

useState()에서는 설정하고 싶은 다음 상태를 직접 지정해주는 방식으로 업데이트
useReducer()에서는 action을 기반으로 상태 업데이트, 업데이트 시 action참조
업데이트 시 참조하고 싶은 값이 있다면 dispatch({})안에 넣어주면 됨

useReducer는 상태 업데이트를 Component에서 분리시킬 수 있음
다른 파일에서 작성 후 불러오는 것도 가능

reducer : 상태를 업데이트하는 함수

function reducer(state, action){
  switch(action.type){
    case '~~':
      return //do Something
  }
}

형태는 위와 같음

reducer는 현재 상태와 action객체를 매개변수로 받아와서 새로운 상태를 반환해 줌
reducer함수를 useReducer의 첫번째 매개변수로 넣어줘야 함

const [number, dispatch] = useReducer(reducer, 0);

0은 number의 초기값이자 기본값임
숫자 뿐 아니라 문자열, 객체도 가능

number : 현재 상태
dispatch : action을 발생시키는 함수 JSP에서의 forwardDispatcher처럼 보내는 의미

import React, { useState } from "react";

function Counter() {
  const [number, setNumber] = useState(0);
  const onIncrease = () => {
    setNumber(prevNumber => prevNumber + 1);
  };
  const onDecrease = () => {
    setNumber(prevNumber => prevNumber - 1);
  };
  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

useState로 구현한 단순한 카운터 프로그램

import React, { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      throw new Error("Unhandled action");
  }
}

function Counter() {
  const [number, dispatch] = useReducer(reducer, 0);
  const onIncrease = () => {
    dispatch({ type: "INCREMENT" });
  };
  const onDecrease = () => {
    dispatch({ type: "DECREMENT" });
  };
  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

useReducer로 구현한 단순한 카운터 프로그램
정리하면 useReducer()의 두번째 매개변수인 0이 number에 처음 적용이 되고, +1버튼이 클릭되면, dispatch에 의해 action이 발생하고 reducer함수가 동작 state는 초기값이자 number값과 동일한 0이고, +1을 해서 1을 return

-1도 마찬가지로 dispatch에 의해 현재 number의 값이 state로 전달되고 계산된 값 state-1return

두번째 예제, onToggleonRemove기능이 있는 페이지 기능 구현

      <UserList
        users={users}
        onToggle={onToggle}
        onRemove={onRemove}
      ></UserList>

Component에 다음처럼 넘겨주는 App.js가 있다고 가정
user들에는 id가 있다. 따라서, onToggle이나 onRemove 클릭시, id를 전달받을 수 있음

<button onClick={() => onRemove(id)}>삭제</button>

위의 경우 App.js 에서 처리 방법은 다음과 같음

function reducer(state, action) {
  switch (action.type) {
    case "TOGGLE_USER":
      return {
        ...state,
        users: state.users.map(user =>
          user.id === action.id ? { ...user, active: !user.active } : user
        )
      };
    case "REMOVE_USER":
      return {
        ...state,
        users: state.users.filter(user => user.id !== action.id)
      };
    default:
      throw new Error("Unhandled action");
  }
}

dispatch 부분은 밑과 같음

const onToggle = useCallback(id => {
    dispatch({
      type: "TOGGLE_USER",
      id
    });
  }, []);

  const onRemove = useCallback(id => {
    dispatch({
      type: "REMOVE_USER",
      id
    });
  }, []);

UserList Component로부터 받은 id값을 dispatch를 통해 reducer함수에 전달

//onToggle
users: state.users.map(user =>
  user.id === action.id ? { ...user, active: !user.active } : user
)

위의 경우에서 usersreturn되어 onToggle함수 안에 쓰이는 배열형 객체
state.usersdispatch를 호출한 시점에서 넘겨지는 state

//useReducer 사용부분
const [state, dispatch] = useReducer(reducer, initialState);

쉽게 풀어서 말하면 dispatch로 호출한 시점의 state를 사용해 새로운 상태를 만들고 (위를 예로 들면 state.users가 새로운 상태로 변경됨) 그것을 return하면, 새로운 state가 호출한 시점의 state를 덮어씌우게 됨

즉, function App()statefunction reducer(state, action)state는 같으면서 같지 않음. dispatch로 호출시 App statereducer state가 되지만, 후에 reducer statereturn한 값이 App state가 됨

profile
코딩의 고수가 되고 싶은 종한이

0개의 댓글