useReducer (TypeScript) 정리

ryuyh2000·2022년 3월 29일
0

#React

목록 보기
2/4

React를 계속 사용하다보니 사용하던것만 사용한다. (useState,useEffect)
그래서 그런지 코드가 계속 길어지고 나중에 유지보수 작업을 하려고 내 코드를 보면 가끔 멀미가 날 것 같다... 그래서 React Hooks 에 대한 무지함 타파하기 위해 사용하던것 이외에 것을 공부 하려고 한다.

우선 기본 꼴은 이렇다

const reducer= (state,action)=>{
	if(action==='up){
    return state+1;
    }
}

[state,dispatch]=useReducer(reducer,0)
dispatch('up')

reducer 부분은 전역 함수형태로 선언을 해준뒤 메인 함수에 useReducer를 선언하는 식이다.

진행 방식은 위 코드를 보면 'up'이라는 값을 매개변수로 dispatch 를 통해 reducer 로 간다. 그 후에 그 값은 action에 할당이 되며 밑으로 조건문을 통해 실행 되는 식이다.

action위와 같은 형태가 아닌 object 형태로 처럼 사용을 할 수 있다.
ex)

interface actionType {
  type: string;
  count: number;
}

const reducer = (state: number, action: actionType): number => {
  if (action.type === "up") {
    return state + 1;
  } else {
    return state;
  }
};
          .
          .
          .
const App =()=>{
const [state,dispatch]=useReducer(reducer,0);

return(
	<button
        onClick={() => {
          dispatch({ type: "add", count: 1 });
        }}
      >
        add
   	</button>
          .
          .
          .
    )
}

useReducer를 사용 하는 이유는 useState를 적게 사용할 수 있다는 이유가 있다.

import React, { useReducer } from "react";

interface actionType {
  type: string;
  count: number;
}

const reducer = (state: number, action: actionType): number => {
  if (action.type === "add") {
    return state + 1;
  } else if (action.type === "sub") {
    return state - 1;
  } else {
    return state;
  }
};

const UseReducerApplication = () => {
  const [count, dispatch] = React.useReducer(reducer, 0);

  return (
    <>
      <button
        onClick={() => {
          dispatch({ type: "add", count: 1 });
        }}
      >
        add
      </button>
      {count}
      <button
        onClick={() => {
          dispatch({ type: "sub", count: -1 });
        }}
      >
        sub
      </button>
    </>
  );
};

export default UseReducerApplication;

만약 위 코드를 useReducer를 사용하지 않고 구현 한다면

const App = () => {
  const [count,setCount]=React.useState(0)

  const up = () => {
    setCount(count+1)
  };

  const down = () => {
    setCount(count-1)
  };

  return (
    <>
      <button onClick={up}>up</button>
      <button onClick={down}>down</button>
      {count}
    </>
 	)
}

state를 2번을 사용하게 된다. 해당 코드는 간략하니 이정도면 그냥 개념적으로도 쉬운 useState를 사용해야하나? 이거 억지로 있어보이는 코드 진행 박식 아닌가? 라고 생각 할 수 있다 (나도 그랬다). 이 상황과 다르게 state의 값이 만약

const studentInfo={
	name:'인욱',
    info:{
    	age:27,
        country:'korea'
    }
}
          .
          .
          .
const [info ,setInfo]=React.useState(studentInfo)

이렇다면 어떻게 정보를 수정할 수 있을까?

만약 useReducer를 사용하지 않는다면

  const [stuInfo, setStuInfo] = React.useState(studentInfo);

  const changeAge = () => {
    setStuInfo((res) => ({ ...res, info: { ...res.info, age: 19 } }));
  };
  const changeCountry = () => {
    setStuInfo((res) => ({ ...res, info: { ...res.info, country: "USA" } }));
  };
  const changeName = () => {
    setStuInfo((res) => ({ ...res, name: "찬호" }));
  };
  return (
    <>
      {stuInfo.info.age}
      {stuInfo.info.country}
      {stuInfo.name}

      <button onClick={changeAge}>change age</button>
      <button onClick={changeCountry}>change Country</button>
      <button onClick={changeName}>change Name</button>
    </>
  );

위 코드를 보면 처음 작성할때는 쉽게 넘어간다. 하지만 유지보수를 한다고 가정했을때 하나 하나 어디에서 사용되며 무엇에 변화가 일어나는지 보는데 오래걸릴 뿐만아니라 가독성 또한 좋지않은 것 같다. 그리고 useState 특성상 변화가 생기면 처음부터 다시 생성하는 특성있는데 큰 프로젝트에서 큰 object를 useState를 이용하여 바꾼다면 최적화면에서도 좋지않다. 물론 하나의 state에 변화를 준다면 useState가 훨씬 좋다.

이번엔 useReducer를 사용한다면

interface studentInfoType {
  name: string;
  info: {
    age: number;
    country: string;
  };
}

interface actionType {
  type: string;
  infomation: {
    age?: number;
    country?: string;
    name?: string;
  };
}

const studentInfo = {
  name: "인욱",
  info: {
    age: 27,
    country: "korea",
  },
};

const reducer = (
  state: studentInfoType,
  action: actionType
): studentInfoType => {
  let newState = state;
  if (action.type === "age") {
    newState = {
      ...state,
      info: { ...state.info, age: action.infomation.age! },
    };
    return newState;
  } else if (action.type === "country") {
    newState = {
      ...state,
      info: { ...state.info, country: action.infomation.country! },
    };
    return newState;
  } else if (action.type === "name") {
    newState = { ...state, name: action.infomation.name! };
    return newState;
  } else {
    return newState;
  }
};

const App = () => {
  const [stuInfo, dispatch] = useReducer(reducer, studentInfo);

  return (
    <>
      {stuInfo.info.age}
      {stuInfo.info.country}
      {stuInfo.name}
      {console.log(stuInfo)}

      <button
        onClick={() => dispatch({ type: "age", infomation: { age: 19 } })}
      >
        change age
      </button>
      <button
        onClick={() =>
          dispatch({ type: "country", infomation: { country: "USA" } })
        }
      >
        change Country
      </button>
      <button
        onClick={() => dispatch({ type: "name", infomation: { name: "찬호" } })}
      >
        change Name
      </button>
</>

사실 useState를 사용하는게 위 코드보다 처음 접했을때 덜 멀미날 것 같다. 하지만 코드를 하나하나 뜯어보면 typescirpt로 코딩을 하다보니 처음부분은 interface 부분이라 제외하면 그 밑에 부분은 결국 useState를 useReducer로 전역함수로 선언 해준것이나 마찬가지다. 이렇게 생각하면 코드리뷰나 유지보수를 할 때 더 쉽게 볼 수 있지 않을까?? 라는 믿음이 생겼다.

그렇다고 useReducer를 useState로 대체하자! 이것보다는 서로 사용할때를 잘 판단하여 알맞게 사용하는 것이 맞다 생각한다.

3줄 요약)

  1. useReducer를 쓰면 맛이 아주 좋아진다
  2. 그렇다고 useReducer를 useState의 대체품으로 생각하지말자 (다르다)
  3. 상황봐서 알아 잘 쓰자
profile
응애 프론트앤드 개발자

0개의 댓글

관련 채용 정보