달달 쇼핑에서는 SVG Sprites
로 아이콘 컴포넌트를 만든다.
약 3주 전, 한 가지 문제가 발생했는데, 특정 상황에서 아이콘이 렌더링되지 않는 문제가 생겼다.
(원래는 좌측 상단에 뒤로가기를 위한 아이콘이 존재하나 렌더링 되지 않는 상황의 이미지이다.)
원인을 알기 위해 어떤 상황에서 문제가 일어나는지 파악해보았다.
추가적인 정보를 얻기 위해 네트워크를 뜯어보던 중 한 가지 사실을 알 수 있었다.
아이콘이 제대로 렌더링되지 않는 경우에는 이미지를 받아온 이후에도 아이콘 요청이 또 발생한다.
반면, 아이콘이 제대로 렌더링되는 경우에는 이미지를 받아온 이후에는 아이콘 요청이 새로 발생하지 않는다.
우리 서비스에서 타 서비스로 넘어갔다 돌아오면 아이콘을 다시 그리기 위해 요청을 날리고, 이 부분이 (알 수 없는 이유로) 제대로 동작하지 않아 일부 아이콘이 보이지 않는 것이구나 추측하였다.
- 일부 기기에서만 일어나는 오류인 것으로 미루어 보아 크로스 브라우징 이슈인 것 같다.
svg를 매번 로딩하지 않고 미리 로딩하면 해결될 것이라고 생각했다.
기존 코드에서는 svg를 svg 파일로 관리하고 있었는데, 이를 변수에 담아 저장해주었다.
const svgSpriteCode = (
<svg xmlns="http://www.w3.org/2000/svg">
...
</svg>
);
createPortal
을 사용하여 1번에서 만든 svg 변수를 body에 넣어주었다.
const GlobalSVGSprite = () => {
return createPortal(svgSpriteCode, document.body);
};
2번에서 만든 GlobalSVGSprite
컴포넌트를 App에서 불러온다.
const App = () => {
return (
<>
...
<GlobalSVGSprite />
</>
);
};
위와 같이 코드를 변경하고 나면 아이콘이 로딩되지 않던 문제가 해결된다.
추가로, 초반에 GlobalSVGSprite를 한 번 호출하기만 할 뿐, 자주 호출되던 icon.svg가 network에서 사라진다. (워낙 크기가 작은 파일이라 성능에 큰 차이는 없겠지만 이게 바로 최적화...?)
아이콘 문제는 해피하게 해결되었지만, 또 다른 문제가 발생하기 시작했다.
페이지 하단에 알 수 없는 영역이 추가되면서, 이중 스크롤이 생기기 시작했다. 코드에서 변경된 부분은 portal 부분밖에 없으므로 해당 영역은 portal에서 차지하고 있는 영역일 것이라 판단했다.
<body>
<div id="root"></div>
<div id="svg-sprite" style="display: none"></div>
...
</body>
따라서, index.html
에서 svg를 로딩하기 위한 (영역을 차지하지 않는) div를 하나 만들고,
const GlobalSVGSprite = () => {
const svgSpriteElement = document.getElementById('svg-sprite');
if (!svgSpriteElement) {
return null;
}
return createPortal(svgSpriteCode, svgSpriteElement);
};
GlobalSVGSprite
가 해당 div에 portal을 만들 수 있도록 위와 같이 코드를 변경해주어 해결하였다.
이제 모든 문제가 해결되었다!
오늘도