"react": "^18.2.0",
"typescript": "^4.9.5",
"react-redux": "^8.1.1",
"@reduxjs/toolkit": "^1.9.5",
Redux toolkit 공부 정리 - [SEB_FE_45] 2023.06.21 / Redux & Reduxjs/toolkit & React-redux
Redux toolkit을 학습하고 프로젝트에 적용해보았다.
개념을 이해하고 적용하는 것까지는 무리없이 마무리하였지만,
다음 부분에서 고민이 되었다.
이에 대한 고민을 정리한 내용을 담아보려고 한다.
우선 화면을 보면 크게 mini 달력과 main 달력과 GNB 영역으로 나눌 수 있다.
그리고 전역적으로 저장해야할 state는 크게 drilldownView와 viewDate로 나뉘었다.
처음에는 깊이 생각하지 못하고 이곳 저곳에서 action 함수를 호출하고 react-router-dom의 navigate 함수를 호출하였다.
그러다보니 불필요한 action 함수 호출과 url이 여러번 변하는 등의 문제가 발생하였다.
코드를 정리한채 나름의 규칙을 세웠다.
url과 state(viewDate와 drilldownView)는 서로서로 영향을 줘야하는 상황이기 때문에
navigate 코드가 이곳저곳에 있을 경우 코드를 읽기도 어렵고 어떤 반응이 일어날지 예상하기도 힘들었다.
따라서 이 둘이 서로 영향을 주는 코드는 상위 컴포넌트에 정리해야겠다는 생각이 들었다.
케이스를 둘로 나누었다.
1. Case 1. url이 수정되는 경우
2. Case 2. state를 수정하는 경우
두번째 케이스는 생각하기 쉬웠다.
이미 상태가 바뀌었으니 url만 수정해주면 된다!
useEffect(() => {
// Case 2. state를 수정하는 경우
navigate(`${drilldownView}/${viewDate.year}/${viewDate.month}/${viewDate.date}`);
}, [drilldownView, viewDate.year, viewDate.month, viewDate.date])
하지만 첫번째 케이스는 생각해야할 것들이 있었다.
1 - 1. 사용자가 url 을 정상적으로 입력하지 않은 경우 ex) mon/2023//
if (!params.drilldownView || !params.year || !params.month || !params.date) {
const today = moment().format();
const temp = getViewDateObj(today);
dispatch(changeDrilldownView('month'));
dispatch(changeViewDate(temp));
return;
}
1 - 2. 기존 url과 동일한 url을 입력한 경우
1 - 3. url에서 drilldownView 부분이 다른 경우
if (drilldownView !== params.drilldownView
&& (params.drilldownView === 'month'
|| params.drilldownView === 'week'
|| params.drilldownView === 'day')
) {
dispatch(changeDrilldownView(drilldownView));
}
1 - 4. url에서 날짜부분(pathDate)이 다른 경우
if (isDiffBetweenViewDateAndPathDate(viewDate, pathDate)) {
dispatch(changeViewDate({ year: pathDate.year, month: pathDate.month, date: pathDate.date }));
}
Main 컴포넌트의 useEffect 전체 코드
const { viewDate, drilldownView } = useAppSelector((state) => state.main);
const dispatch = useAppDispatch();
const navigate = useNavigate();
const params = useParams();
const pathDate = { year: params.year || '', month: params.month || '', date: params.date || '' };
useEffect(() => {
// Case 1. url이 수정되는 경우
// Case 1 - 1. url 을 정상적으로 입력하지 않은 경우 -> 오늘 날짜로 수정 및 이동
if (!params.drilldownView || !params.year || !params.month || !params.date) {
const today = moment().format();
const temp = getViewDateObj(today);
dispatch(changeDrilldownView('month'));
dispatch(changeViewDate(temp));
return;
}
// Case 1 - 2. url이 기존과 동일할 경우 -> 수정 필요 없음
if (drilldownView === params.drilldownView && !isDiffBetweenViewDateAndPathDate(viewDate, pathDate)) {
return;
}
// Case 1 - 3. url에서 drilldownView 부분이 다른 경우 -> state 수정
if (drilldownView !== params.drilldownView
&& (params.drilldownView === 'month'
|| params.drilldownView === 'week'
|| params.drilldownView === 'day')) {
dispatch(changeDrilldownView(drilldownView));
}
// Case 1 - 4. url에서 날짜 부분이 다른 경우 -> state 수정
if (isDiffBetweenViewDateAndPathDate(viewDate, pathDate)) {
dispatch(changeViewDate({ year: pathDate.year, month: pathDate.month, date: pathDate.date }));
}
}, [drilldownView, params.year, params.month, params.pathDate])
useEffect(() => {
// Case 2. state를 수정하는 경우
navigate(`${drilldownView}/${viewDate.year}/${viewDate.month}/${viewDate.date}`);
}, [drilldownView, viewDate.year, viewDate.month, viewDate.date])
정리해보면 너무나 당연한 이야기이지만 정작 state를 다루려고 하는 상황이 오면 꼭 헤매는 것 같다.
프로젝트들을 통해 state를 관리하는 경험을 많이 쌓아 직관적으로 state를 관리할 곳을 바로 찾을 수 있도록 해야겠다.