과제 체크포인트
배포: https://jihoon-0330.github.io/front_6th_chapter4-2/
과제 요구사항
-
배포 후 url 제출
-
API 호출 최적화(
Promise.all이해) -
SearchDialog 불필요한 연산 최적화
-
SearchDialog 불필요한 리렌더링 최적화
-
시간표 블록 드래그시 렌더링 최적화
-
시간표 블록 드롭시 렌더링 최적화
과제 셀프회고
리액트에서 최적화를 한다고 하면 메모이제이션만을 생각했었는데, 이번에 과제를 진행하면서 사용중인 라이브러리의 옵션 설정, 컨텍스트의 위치 등 다른 요인들도 크게 작용한다는 것을 느낄 수 있었다. 라이브러리르 도입할 땐 해당 라이브러리가 렌더링에 어떤 영향을 줄 수 있는지 어떻게 최적화 시킬 수 있는지 꼼꼼히 살펴봐야겠다는 생각이 들었다.
코드 품질
중복 요청을 방지하는 캐시 시스템을 만들었습니다.
현재는 Lecture 타입만 사용하도록 되어있지만, 제너릭으로 변경하면 더 유연한 사용이 가능할 것 같습니다.
const createApiCache = () => {
const cache = new Map<string, Promise<AxiosResponse<Lecture[], unknown>>>();
return (url: string) => {
const cached = cache.get(url);
if (cached) {
return cached;
}
const result = axios.get<Lecture[]>(url);
cache.set(url, result);
result.finally(() => {
cache.delete(url);
});
return result;
};
};
핸들러 안에서 zustand 상태값을 직접 접근해 리렌더링을 최소화 했습니다. 현재 프로젝트에선 이렇게 작성해도 문제가 발견되지 않았지만 리액트에서 상태를 사용하는 일반적인 패턴이 아니기도 하고 주의해야 할 점이 있을 것 같습니다.
const handleDragEnd = (event: any) => {
...
const { schedulesMap } = useSchedules.getState();
...
}
App 에서 사용중이던 ScheduleDndProvider 의 위치를 변경해 영향을 받는 컴포넌트를 최소화 했습니다.
...
<ScheduleDndProvider>
<ScheduleTable
key={`schedule-table-${index}`}
schedules={schedules}
tableId={tableId}
onScheduleTimeClick={(timeInfo) =>
setSearchInfo({ tableId, ...timeInfo })
}
onDeleteButtonClick={({ day, time }) =>
setSchedulesMap((prev) => ({
...prev,
[tableId]: prev[tableId].filter(
(schedule) =>
schedule.day !== day || !schedule.range.includes(time),
),
}))
}
/>
</ScheduleDndProvider>
...
드래그를 할 때 시각적으로 보이지 않는 위치에 리렌더링 하이라이트가 표시 되었는데, 확인해보니 강의를 삭제하는 Popover 가 존재하기 때문이었다. 처음엔 드래그 상태에 따라 Popover 컴포넌트를 렌더링 하지 않는 방식으로 시도를 했었는데, 라이브러리를 찾아보니 열릴 때 렌더링 되도록 지연하는 옵션이 있어 옵션을 추가하는 것으로 간단하게 최적화 할 수 있었습니다.
<Popover isLazy>
...
학습 효과 분석
- 렌더링 최적화를 위한 다양한 방법을 알게 되었다.
- 라이브러리를 사용할 때 리렌더링에 대해 주의해야 함을 인지하게 되었다.
과제 피드백
항상 테스트 코드를 통해 과제의 통과 여부를 알 수 있엇는데, 렌더링 최적화에서는 테스트가 없다 보니 과제의 요구사항을 만족하는지 확신을 가지기 어려웠던 것 같습니다. 그래서 다른 사람들과 서로 확인을 해주기도 했는데 재밌었습니다.
리뷰 받고 싶은 내용
리렌더링을 줄이기 위해 상태 값을 함수에서 접근하도록 했는데, 실무에서 해당 방식을 사용해도 문제가 없을까요?
const handleDragEnd = (event: any) => {
...
const { schedulesMap } = useSchedules.getState();
...
}
과제 피드백
고생하셨습니다 지훈님 벌써 10주가 지나갔네요! 10주간 기억에 날만큼 정말 열심히 해주셔서 저도 많이 배웠던 것 같습니다. 이번 과제도 정말 잘 해주셨고, 역시나 다른 분들과 이야기 많이 해주시면서 진행했던 것 같네요 :+1
리렌더링을 줄이기 위해 상태 값을 함수에서 접근하도록 했는데, 실무에서 해당 방식을 사용해도 문제가 없을까요?
저는 오히려 이런 부분이 zustand에서 어느 정도 의도한 부분의 맥락이라고도 생각했긴 했어요 ㅎㅎ 명확한 사용에 대해 차이점을 이해하고 최적화를 한다면 크게 문제는 없을 것 같아요. 대신에 이런 작성법이 다른 누군가가 봤을때 익숙하지 않아 바깥으로 빠질 수 있으니, 주석으로 명시적이게 어떤 의도였는지 남겨준다면 충분하지 않을까! 싶습니다.
고생하셨고, 앞으로 개발인생 화이팅 하세요! 그럼 내일봬요~