누구나 쉽게 접할 수 있는 기본적인 프로젝트로 시작하여 배웠던 내용들을 적용시켜 보고, 스스로 생각한 기능을 구현한다면 복습과 더불어 성취감까지 얻을 수 있다고 생각해서 시작한 프로젝트 모음입니다. 그 중 첫번째 프로젝트 주제로 Todo-List로 정했습니다.
'추가, 완료, 삭제, 수정' 기본적인 기능 구현만 기본적으로 완료되어 있는 상태입니다. 아래의 사진은 각각 구현된 화면과 컴포넌트 구조도입니다.
prop drilling이란 컴포넌트 트리 구조에서 상위 컴포넌트로부터 하위 컴포넌트로 prop를 계속해서 전달해서 생기는 패턴입니다.
현재 구현된 Todo-list에는 상태 관리 라이브러리가 없기 때문에 TodoBoard 컴포넌트에서 3단계 아래에 있는 TodoEdit 컴포넌트까지 prop이 전달됩니다. prop drilling를 사용하면 코드의 유지 보수가 어려워지고, 성능 저하 등 여러가지 문제점이 발생할 수 있어 최대한 피해야 합니다.
아래는 redux-toolkit을 적용하면서 생긴 폴더 구조입니다.
/store
├ index.ts
├ /slice
└ todoData.ts
/hooks
└ index.ts
todoData.ts (slice)
위의 코드는 todoData를 전역으로 관리하기 위해 작성한 slice코드 입니다. 위의 코드는 TodoBoard.tsx에서 작업했던 할 일 생성, 삭제, 수정, 완료 등의 대신 처리하게 됩니다.
redux를 사용한 덕분에 복잡했던 TodoBoard.tsx가 깔끔해진걸 확인 할 수 있습니다.
코드를 살펴보면 일반적인 React에서 사용하는 store의 index와 다른점이 있습니다. 바로 RootState와 AppDispatch입니다. 각각 Redux 상태의 타입을 나타내고, disPatch의 타입을 가져옵니다.
다른 component에서 Redux의 상태를 사용(useSelector)하거나, dispatch(useDispatch) 함수를 사용할 때 사용하게 됩니다. 이는 typescript를 사용하므로 타입을 지정하기 때문에 코드의 안정성을 높이고 버그를 줄이게 됩니다.
이 코드는 useSelector와 useSelector의 커스텀 훅입니다. Redux-toolkit의 공식 문서에서 지향하고 있는 코드 패턴입니다. 위의 코드 패턴이 필요한 이유는 다음과 같습니다.
useSelector의 경우, 매번 (state: RootState)와 같이 타입을 지정할 필요가 없어짐
// 커스텀 훅을 사용하지 않을 경우 매번 타입 지정 필요 const todoDatas = useSelector((state: RootState) => state.todoData); // 커스텀 훅 덕분에 번거롭게 타입 지정을 하지 않아도 괜찮음 const todoDatas = useAppSelector((state) => state.todoData);
Redux의 Dispatch 타입은 Redux의 thunk 미들웨어에 대해 인식하지 못함
- Thunk는 비동기 작업을 처리하고 Redux의 상태를 변경하는 함수
- 액션을 dispatch하기 위해 useDispatch 사용, thunk 미들웨어에 대해 인식하지 못하기 때문에
'AppDispatch'를 사용해 dispatch 함수의 타입을 확장- 커스텀 훅을 사용하여 dispatch의 타입을 미리 지정하여 action을 처리하고 미들웨어에 맞게 동작
현재 제가 만든 Todo-List의 경우 비동기 작업을 하지 않아 thunk가 필요하지 않으나 공부하며 익숙해지기 위해 추가하였습니다.
아래의 코드는 TodoItem.tsx의 일부분으로 Redux를 사용함으로서 prop를 받지 않아 가독성이 높을 것을 알 수 있습니다.
Redux-toolkit을 처음 배웠을 때는 바로 적용시켜 사용했기 때문에 장점을 확실하게 느끼지 못했습니다. 이번 기회를 통해 Redux-toolkit의 장점을 확실히 느낄 수 있어서 좋았습니다.