Skip to content

렌더링 최적화 2탄: 잘못된 custom hook 사용,, 전체 리렌더링을 부르다,,

Soobeen Yoon edited this page Dec 14, 2022 · 2 revisions

문제 인식

스크린샷 2022-12-14 오후 12 21 44

분명히 렌더링 최적화 일지에서 useMemo, React.memo로 렌더링을 최적화했는데, 합치고 일부 비즈니스 로직을 hook으로 분리했는데 렌더링이 원상태로 돌아왔다.

그 이유는 무엇이었을까..?

문제 원인 파악

🤔 기존에 설계한 구조의 문제

  • useTodoList.tsx에서 모든 상태(todoList, displayTime 등)을 가지고 있었고, 이를 Main에서 받아서 자식 컴포넌트에 내려주는 방식이었다.
  • 컴포넌트 재사용성을 높이는 방법을 구경하던 중, 비즈니스 로직을 따로 hook으로 분리하라는 글을 보고 시간을 제어하는 컴포넌트에서 비즈니스 로직을 분리했다가 오히려 역효과가 난 것이다..!
  • custom Hook은 사용하는 컴포넌트마다 custom hook이 가지는 state, effect는 완전히 독립적이기 때문에 Main 하위의 모든 컴포넌트가 같은 상태를 가질 수 없을 수도 있겠다는 생각이 들어서 props로 내려주었고, 이게 전체 페이지 리렌더링을 야기하는 끔찍한 결과를 낳았다.

Do two components using the same Hook share state?

    No. Custom Hooks are a mechanism to reuse stateful logic (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.


  • 결과적으로, timer 실행 시 재생버튼을 눌러서 소요시간을 보여주는 displayTime이 1초에 한 번 변경되면 페이지 전체가 리렌더링되는 문제가 발생했다.
  • 이러한 문제가 1초에 한번씩 반복되는 것은 꼭 고쳐야 하는 문제라고 인지했다..!!🔥
스크린샷 2022-12-14 오후 3 34 11

해결 방법

  • useTodoList hook을 Main에서 사용해서 props로 상태를 내리는 방식 대신, 필요한 컴포넌트에서 알아서 호출하도록 구조를 변경했다.

해결 과정

  • 여러 컴포넌트에서 재사용할 수도 있는 미루기 기능, 완료 기능만 hook으로 분리하고 나머지는 컴포넌트
  • 이에 따라, Main에서 props로 내려주는 각종 상태를 가지고 있는 불필요한 useTodoList hook을 지울 수 있었음.
스크린샷 2022-12-14 오후 3 34 28

after

스크린샷 2022-12-14 오후 12 23 48

성능 비교

  • Rendering Duration 35% 개선 (timer 움직일 때 displayTime 변경되는 동일 시점 비교)

before

after

스크린샷 2022-12-14 오후 3 45 21

느낀점

  • '컴포넌트 재사용'에 대한 컨셉을 잘못 이해해서 벌어진 실수였던 것 같다. 컴포넌트를 재사용하기 위해서 컴포넌트에서 모든 비즈니스 로직을 분리해야 되는 것이 아니라, 오히려 공통 컴포넌트로 추상화해서 공통 컴포넌트를 재사용하는 방식을 사용하는 것이 훨씬 더 좋은 방법이었을 것 같다. 특히, global state를 사용하면서 전체 리렌더링을 야기하는 방식을 사용하면서까지 component의 로직을 분리하는 것은 악수였던 것 같다..
  • 컴포넌트, custom hook을 설계할 때 상태가 어떻게 흘러가는지 충분히 인지하고 불필요하게 props를 사용하는 것을 지양해야겠다는 생각을 했다.

참고 자료

💊 비타500

📌 프로젝트

🐾 개발 일지

🥑 그룹활동

🌴 멘토링
🥕 데일리 스크럼
🍒 데일리 개인 회고
🐥 주간 회고
👯 발표 자료
Clone this wiki locally