과제 체크포인트
배포링크
https://suhyeon57.github.io/front_6th_chapter4-2/
과제 요구사항
-
배포 후 url 제출
-
API 호출 최적화(
Promise.all이해) -
SearchDialog 불필요한 연산 최적화
-
SearchDialog 불필요한 리렌더링 최적화
-
시간표 블록 드래그시 렌더링 최적화
-
시간표 블록 드롭시 렌더링 최적화
과제 셀프회고
기술적 성장
-
DevTool 활용 React DevTool을 사용해 어떤 컴포넌트가 불필요하게 리렌더링되는지 직접 확인할 수 있었고, 그 과정을 통해 성능 개선 포인트를 찾을 수 있었다.
-
클로저와 캐시 클로저는 변수 접근 패턴이고, 캐시는 성능 최적화 기법이라는 점을 다시 정리할 수 있었다. 특히 둘을 함께 활용하면 안전하면서도 효율적인 코드를 작성할 수 있다는 걸 실감했다.
코드 품질
과제를 진행하면서 컴포넌트 분리를 한 파일 안에서만 처리했고, “나중에 해야지” 하며 미뤄버린 부분이 있었다. 앞으로는 클린 코드를 위해 파일 단위로 폴더 구조를 분리하고, 책임을 명확히 하는 방향으로 개선할 필요가 있다고 느꼈다.
학습 효과 분석
메모제이션
몇 주차인지 기억은 안 나지만, 메모제이션에 대해 배웠기 때문에 간단하게 작성했다.
1. memo
컴포넌트를 메모이제이션하여 props가 변경되지 않으면 리렌더링을 방지합니다.
2. useMemo
값(연산 결과)을 메모이제이션하여 의존성이 변경되지 않으면 재계산을 방지합니다.
3. useCallback
함수를 메모이제이션하여 의존성이 변경되지 않으면 함수 재생성을 방지합니다.
4. useAutoCallback
함수를 메모이제이션하되, 의존성 배열을 자동으로 관리하는 커스텀 훅입니다.
비교표
| 구분 | 대상 | 목적 | 의존성 관리 | 사용 위치 |
|---|---|---|---|---|
| memo | 컴포넌트 | 리렌더링 방지 | props 비교 | 컴포넌트 정의 시 |
| useMemo | 값/연산 | 재계산 방지 | 수동 배열 | 컴포넌트 내부 |
| useCallback | 함수 | 재생성 방지 | 수동 배열 | 컴포넌트 내부 |
| useAutoCallback | 함수 | 재생성 방지 | 자동 감지 | 컴포넌트 내부 |
처음으로 내가 진행한 일 → 컴포넌트 분리 후 memo를 통한 메모제이션 진행
이렇게 체크박스 등 클릭 시 전부 리랜더가 되는 문제가 발생하였다. 나는 컴포넌트 분리를 했는데 도대체 왜!!? 하면서 각각 컴포넌트 별 change 핸들러도 구현해 보고 여러가지 시도를 하였지만, 코드만 늘어갈 뿐 맘에 드는 결과는 나오지 않았다.
결국, 나의 선생님 유누님에게 도움을 요청
유누님은 어디가 문제인지 알려주고,, (놀려도 주심 ㅠ)
결국 문제 점을 찾아내고 해결 완료 !
const TimeSelector = memo(
({
times,
changeSearchOption,
}: {
times: SearchOption["times"];
changeSearchOption: (
field: keyof SearchOption,
value: SearchOption[typeof field]
) => void;
})
searchoption을 전부 전달하지 않고 컴포넌트에 해당하는 지정 값만 전달하도록 변경 후 해결 완료했다.
만약 [searchOptions]SearchDialog.tsx ) 객체 전체를 전달한다면,
- [
searchOptions]SearchDialog.tsx ) 객체의 참조가 바뀜 memo는 얕은 비교로 "props가 변경됨"으로 판단- [
TimeSelector]SearchDialog.tsx )가 불필요하게 리렌더링됨
이러한 문제가 존재하기 때문에 변경해준 것이다.
이 것으로 인해 나는 얕은 비교와 메모제이션에 대해 정확하게 파악할 수 있었다.
과제 피드백
리뷰 받고 싶은 내용
과제 피드백
수고했어요 수현!! 이번 과제는 React 애플리케이션에서 실제 성능 병목 지점을 찾고 최적화하는 것이 목표였습니다.
React DevTools를 활용해서 불필요한 리렌더링을 직접 확인하고 성능 개선 포인트를 찾아낸 과정이 정말 좋았어요. 그리고 클로저와 캐시를 함께 활용해서 안전하면서도 효율적인 코드를 작성한 부분도 잘했습니다. 메모이제이션에 대한 개념 정리도 체계적으로 잘 했네요!
특히 인상 깊었던 건 컴포넌트를 분리했는데도 여전히 리렌더링이 발생하는 문제를 직면했을 때 포기하지 않고 끝까지 해결해낸 과정입니다. searchOptions 객체 전체를 전달하면 참조가 바뀌어서 memo의 얕은 비교에서 변경으로 판단되는 문제를 찾아내고, 컴포넌트에 해당하는 지정 값만 전달하도록 개선한 것이 정말 훌륭해요. 이런 시행착오를 통해 얕은 비교와 메모이제이션의 원리를 정확하게 파악하게 된 거죠.
이런 문제를 겪어본 경험이 정말 소중합니다. memo가 단순히 컴포넌트에 감싸주기만 하면 되는 게 아니라, props를 어떻게 전달하느냐에 따라 효과가 달라진다는 걸 몸소 체험한 거니까요. 객체나 배열을 props로 전달할 때는 항상 참조 동일성을 고려해야 한다는 중요한 개념을 실전에서 익혔네요.
앞으로도 이런 식으로 문제를 만났을 때 차근차근 원인을 분석하고 해결해나가는 습관을 유지하시길 바래요. React DevTools Profiler를 적극 활용해서 "왜 리렌더링이 일어나는가?"를 항상 확인하는 것도 좋은 습관입니다.
성능 최적화는 어떻게 하는지 방법보다도 어디서 병목이 생기는지를 이해하고 찾는 게 더 큰 실력이라고 생각해요. 수현이는 이번에 실제 문제를 만나고 해결하면서 그런 사고 과정을 잘 기른 것 같습니다. 심심할 때마다 어디가 병목이 될까 등을 한번씩 고민해보다 보면 이러한 경험이 쌓여 나중에 복잡한 성능 문제를 만났을 때 어디서부터 접근할지 감이 생기는 거라 생각해요.
지난 10주간 너무 너무 수고 많았어요! 이번 경험들이 앞으로 개발하는 데 있어서 나 스스로 충분히 잘하려고 노력할 수 있구나, 해냈구나 하는 마음으로 새로운 것에 도전하고 성장하는 데 있어 더 쉽게 도전할 수 있게 되는 계기가 되기를 바랍니다. 화이팅입니다!