가수면
display: none 요소는 React.lazy가 적용될까? 본문
의문의 발단은 스터디 톡방에 올라온 코드로부터 시작되었다.
아래는 화면이 md사이즈일 때 요소들이 보이고 안 보이는 것을 조절한 반응형 레이아웃 코드다.
<>
<div className="md:hidden">
<MobileHomeSections.Hero />
<MobileHomeSections.Timeline />
<MobileHomeSections.BusinessHero />
<MobileHomeSections.BusinessMCMS />
<MobileHomeSections.BusinessMGMS />
<MobileHomeSections.ContactHero />
<MobileHomeSections.ContactUs />
<MobileHomeSections.ContactForm />
</div>
<div className="hidden md:block">
<HomeSections.Hero />
<HomeSections.Timeline />
<HomeSections.Direction />
</div>
</>
코드와 함께 올라온 주제는 메인 페이지에서 저 무거운 컴포넌트를 전부 불러오고 있는데 좋은 방법이 없느냐.
나는 아래 display: none요소들을 컴포넌트로 묶어 react lazy를 사용할 것을 권했다.
레이지 로딩을 쓰면 저런 식으로 구성해도 모바일 뷰가 되기 이전에 안 불러오는 것이 맞는지 걱정된다는 말이 돌아왔다.
나는 2가지 이유를 들어 안 불러와질 것이라 답변했다.
1. '반환된 구성 요소를 처음 렌더링하려고 시도할 때까지 호출하지 않습니다.' (리액트 공식 문서에 나와있는 lazy의 설명)
2. display: none이 적용된 요소는 렌더 트리 구축 단계에서 제외된다.
그러므로 react lazy를 사용하면 none이 block으로 바뀌기 전까지 안 불러와질 것이다.
그런데 display: none과 block이 토글 되는 컴포넌트의 상태값이 유지되었던 기억이 있는 걸로 봐선 display: none도 불러오는 것이다라는 다른 의견이 나왔다.
그분 말씀대로 상태값이 유지된다면 컴포넌트가 호출되고 있다는 얘기가 맞을 것이다.
그래서 궁금증이 생겼다.
그럼 렌더 트리 구축 단계에서 제외된다는 나의 지식이 잘못된 걸까, 그분의 기억이 잘못된 걸까?
렌더 트리 단계에서 제외된다는 것은 어떤 의미일까?
직접 해보면 알 일이다.
나는 바로 실험에 돌입했다.
import AComponent from "./components/AComponent";
import BComponent from "./components/BComponent";
export default function App() {
return (
<div>
<AComponent />
<BComponent />
</div>
);
}
const BComponent = () => {
let a = 0;
for (let index = 0; index < 999999999; index++) {
a += index;
}
return <div style={{ display: "none" }}>{a}</div>;
};
export default BComponent;
나는 프로파일러를 통해 display: none이 rendered에 기록되는지 확인할 수 있는 코드를 작성했다.
그분 말씀대로 아예 최초 마운트 때 불러와지는 것을 볼 수 있다.
그렇다면 렌더 트리 단계에서 생략된다는 얘기는 대체 무엇일까?
chat gpt 친구에게 물어봤다.
아하, 그러니까 렌더 트리 단계에서 빠지기 때문에 페인트 되진 않지만, 그 반대로 렌더 트리의 이전 단계들, 그러니까 DOM 트리 단계에서부터 이미 읽힌다는 것으로 이해할 수 있었다.
지식+1이 되는 순간이다
그렇다면 다시 코드로 돌아와서, 어떤 방법이 좋을까?
방법은 두 가지가 있을 것이다.
1. 처음 예상했던 동작과는 다르게 동작하겠지만, 처음 주장했었던 그대로 display:none 컴포넌트를 lazy로 불러온 뒤 fallback 없이 suspense를 입힌다.
2. innerWidth를 이용해 특정 너비에서 토글 되는 상태값을 만들어 컴포넌트의 마운트 자체를 분기처리한다.
2번 방법의 경우는 초기 렌더링 속도가 비교적 빠르겠지만, 자바스크립트에게 작업을 맡김으로써 런타임 성능상 미디어쿼리보단 안 좋을 수밖에 없다.
반면, 1번의 경우 다음 결과를 가져올 것이다.
1. 모바일 뷰 사이즈에서는 lazy를 사용하지 않을 때와 동일하게 로딩되는 동안 흰 화면이 보일 것이므로 ux에 차이가 없다.
2. pc화면에서는 display:none인 컴포넌트가 지연로딩 되는 사이 기타 요소들이 준비되는 대로 렌더링을 마칠 것이기 때문에 TTV 시간을 앞당기는 결과를 가져올 수 있을 것이다.
'일지' 카테고리의 다른 글
포트가 사용 중이 아님에도 'Web server failed to start. Port 8080 was already in use.' 에러가 뜨는 경우 (1) | 2023.12.28 |
---|---|
MySQL Workbench 오류 (0) | 2023.12.14 |
svg 스크롤 애니메이션 (선 그리기) (0) | 2023.10.11 |
랜덤한 요소의 개수 계산해 페이지네이션하기 (0) | 2023.08.29 |
Next에서 jest를 사용할 때 내비게이션 문제 (0) | 2023.08.10 |