2021년 9월부터 약 3개월동안 만들었던 프로젝트의 코드를 오랜만에 리뷰해 보았다.
리팩토링해야 할 부분들이 정말 많았고, 그 중에 한 부분인 토스트 팝업을
적용한 부분에 대해 리팩토링한 과정을 공유해보고자 한다.
유저의 사용감을 향상시키기 위해 기본 alert 대신에 토스트 팝업을 적용했다.
컴포넌트에서 보여줘야 하는 내용이 사용자 인터랙션에 따라 바뀌어야 했기 때문에
useState 훅을 사용해 상태를 관리해줬다.
const [toastState, setToastState] = useState(false);
if (nickName === "" || nickName === null || nickName === undefined) {
setToastState(true);
} else if {
...생략
{toastState && <Toast message="닉네임을 입력해주세요!" />}
만약, 닉네임 입력란이 비어있다면 toastState값이 true로 변경되고
토스트 팝업이 나타나게 된다.
그리고 toastState를 false로 초기화시켜 주어야 하기 때문에 useEffect 훅을 사용했다.
useEffect(() => {
if (toastState) {
setTimeout(() => {
setToastState(false);
}, 1500);
}
}, [toastState]);
toastState값이 변경되면 useEffect 훅이 실행되고 toastState의 값이 true라면
1500 밀리초 후에 초기값인 false로 다시 변경하는 방식이다.
useEffect(() => {
if (toastState) {
setTimeout(() => {
setToastState(false);
}, 1500);
}
}, [toastState]);
useEffect(() => {
if (secondToastState) {
setTimeout(() => {
setSecondToastState(false);
}, 1500);
}
}, [secondToastState]);
useEffect(() => {
if (editToastState) {
setTimeout(() => {
setEditToastState(false);
}, 1500);
}
}, [editToastState]);
useEffect(() => {
if (userToastState) {
setTimeout(() => {
setUserToastState(false);
}, 1500);
}
}, [userToastState]);
useEffect(() => {
if (maxTextState) {
setTimeout(() => {
setMaxTextState(false);
}, 1500);
}
}, [maxTextState]);
위와 같이 동일한 구조의 useEffect 훅이 점점 많아졌고, 전체 프로젝트에서
36번이나 반복된다는 사실을 알게 되었다. 기능은 문제없이 잘 실행되고 있었지만,
코드가 너무 길어져 가독성이 떨어지고 나중에 setTimeout의 시간 값을 바꾸는 경우,
수정이 굉장히 힘들 것이라는 생각이 들었다.
src --> hooks --> useToast.js
import { useEffect } from "react";
function useToast(state, setState) {
useEffect(() => {
if (state) {
setTimeout(() => {
setState(false);
}, 1500);
}
}, [state, setState]);
}
export default useToast;
상태값(state)과 상태값을 변경시키는 함수(setState)를
인자로 받는 useToast라는 커스텀 훅을 만들었으며,
아래와 같이 조금 더 깔끔하게 코드를 작성할 수 있었다.
import useToast from "../../hooks/useToast";
useToast(toastState, setToastState);
useToast(secondToastState, setSecondToastState);
useToast(editToastState, setEditToastState);
useToast(userToastState, setUserToastState);
useToast(maxTextState, setMaxTextState);
import { _deleteToast } from "../../redux/modules/cat";
const deleteToast = useSelector((state) => state.cat.deleteToast);
useEffect(() => {
if (deleteToast) {
setTimeout(() => {
dispatch(_deleteToast(false));
}, 1500);
}
}, [deleteToast]);
위와 같이 useSelector 훅과 useEffect 훅을 사용해서 코드를 작성한 부분도
5번 반복되고 있었고, useToast를 만들었던 방식과 동일한 방식으로
useDispatchToast라는 커스텀 훅도 만들었다.
src --> hooks --> useDispatchToast.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
function useDispatchToast(state, toast) {
const dispatch = useDispatch();
useEffect(() => {
if (state) {
setTimeout(() => {
dispatch(toast(false));
}, 1500);
}
}, [state, toast, dispatch]);
}
export default useDispatchToast;