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줄 요약)
- useReducer를 쓰면 맛이 아주 좋아진다
- 그렇다고 useReducer를 useState의 대체품으로 생각하지말자 (다르다)
- 상황봐서 알아 잘 쓰자