App.tsx
의 라우팅 구조는 다음과 같았다.
<Switch>
<Route exact path="/" component={() => <Redirect to={{ pathname: '/map' }} />} />
<Route path="/map" component={MainPage} />
<Route path="/github/callback" component={LoadingPage} />
<PrivateRoute path="/profile" component={ProfilePage} />
<Route component={NotFoundPage} />
</Switch>
<PrivateRoute path="/map/write-review" component={ReviewSubmitPage} />
<Route path="/map/ranking" component={RankingPage} />
<Route path="/map/signin" component={SignInPage} />
<PrivateRoute path="/map/signup" component={SignUpPage} />
<PrivateRoute path="/profile/update-address" component={ProfileAddressPage} />
/map/ranking
, /map/signin
등 </Switch>
아래에 있는 Route
는 모두 "배경" 컴포넌트 위에 모달을 띄운다.
모달이 띄워지는 URL로 접근하면
Switch-path
를 통해 배경 컴포넌트가 렌더링되고(/map
또는 /profile
)Route
중에서 /map/ranking
, /profile/update-address
등 일치하는 경로의 모달 컴포넌트가 렌더링 되어배경 페이지 위에 모달이 띄워지는 방식으로 작동한다.
이 방식의 문제점은 모달이 띄워질 때마다 불필요하게 배경 컴포넌트가 재렌더링된다는 것이다.
헤더 아래 MainPage
컴포넌트가 불필요하게 재렌더링되고있다. 중앙 마커 주변 테두리에 주목. 참고로 헤더는 useLocation
훅을 사용하기 때문에 상태변화에 의해 재렌더링되고 있다.
모달을 띄우고 닫는 총 네 번 MainPage
컴포넌트가 렌더링되었다.
불필요한 재렌더링을 방지하는 방법중 하나로 **React.memo
**가 있다.
React.memo
는 컴포넌트를 memorizing해 놓았다가 나중에 같은 컴포넌트를 렌더링할 필요가 있을 때 props
변화가 없다면 memoized된 컴포넌트를 그대로 재사용하여 불필요한 렌더링을 없애는 성능 최적화 방법이다.
물론 컴포넌트 내 상태변화에 의한 재렌더링은 원래대로 재렌더링이 되고, 오직 props
변화에만 대응하여 기존 컴포넌트를 재사용할지 결정한다.
보통 다음과 같이 사용한다. 많은 경우 export
문을 조금만 수정하면 되고, props
에 콜백함수 등이 있을 경우 useCallback
으로 감싸주는 등 약간의 노력을 기울이면 된다.
function MyComponent(props) {
/* props를 사용하여 렌더링 */
}
export default React.memo(MyComponent);
React.memo
를 MainPage
와 MainPage
하위 MapComponent
에 걸어주어 결과를 지켜보았다. 불필요한 재렌더링을 어느정도 줄일수 있었지만...
// MainPage.tsx
export default React.memo(MainPage);
// Map.tsx
export default React.memo(MapComponent);
중앙 마커 주변 테두리가 그려지지 않는다. MapComponent
는 더이상 재렌더링되지 않는다.
MapComponent
가 한번도 렌더링되지 않았다.
MainPage
컴포넌트는 여전히 총 4번 렌더링이 되었다.
MapComponent
의 렌더링 문제는 해결했지만 MainPage
의 렌더링은 여전히 이어지고 있었다.