
Nuxt 코드를 살펴보는도중 ClinentOnly를 이용하여 svg아이콘을 처리하는 코드를 봤습니다. 실제 화면에서도 켄텐츠가 모두 렌더링되고 아이콘이 뚝하고 나오는 모습을 봤고 당장 개선하고싶은 마음에 clientOnly라는 컴포넌트를 조사하게 되었습니다. 이 글은 'ClientOnly가 최선인지'에서 시작해서 의식의 흐름대로 찾아보고 정리한 글입니다. 가벼운 마음으로 읽어주시면 감사하겠습니다 😄
이 문서는 React 기반 SSR/CSR 렌더링에서 자주 등장하는 개념들인 hydration, layout shift, skeleton UI, chunk, @loadable/component, 그리고 Emotion에 대해 자세히 설명합니다.
<ClientOnly> 컴포넌트<ClientOnly>를 사용하면 SSR 단계에서는 렌더하지 않고, CSR 시점에만 컴포넌트를 렌더함<ClientOnly>의 fallback 슬롯에 임시 공간 (height 확보)을 넣어주면 레이아웃 안정 가능import loadable from '@loadable/component';
import { CSSTransition } from 'react-transition-group';
import './fade.css';
const HeavyComponent = loadable(() => import('./HeavyComponent'), {
fallback: <Skeleton />
});
function App() {
const [show, setShow] = useState(false);
return (
<Suspense fallback={<Skeleton />}>
<CSSTransition in={show} timeout={300} classNames="fade" unmountOnExit>
<HeavyComponent />
</CSSTransition>
</Suspense>
);
}
Suspense: 비동기 컴포넌트 로딩 시 fallback 처리Skeleton: loading 동안 자리 확보CSSTransition: 콘텐츠가 부드럽게 fade-in 되는 효과yarn add @emotion/react @emotion/styled
import styled from '@emotion/styled';
const Button = styled.button`
background: hotpink;
padding: 8px 16px;
`;
const style = css`
color: blue;
`;
<div css={style}>Emotion 스타일</div>
styled-components와 문법 유사css prop, Global, keyframes 같은 기능은 Emotion만의 장점@loadable/component 개념과 preloadReact.lazy는 SSR에서 작동하지 않음@loadable/component는 SSR에서도 사용할 수 있도록 설계됨ChunkExtractor를 통해 필요한 JS chunk를 미리 불러올 수 있음loadable-stats.json 생성| 항목 | 설명 |
|---|---|
| Chunk | 앱을 기능별로 나눈 JS 파일. 페이지/컴포넌트 단위로 분리됨 |
| .min.js | JavaScript를 압축한 버전 (줄바꿈 제거, 변수 짧게) |
즉,
chunk는 파일 역할.min.js는 파일 형태 (최적화)| 단어 | 뜻 | 개발에서 의미 |
|---|---|---|
| Junk | 쓰레기, 불필요한 것 | 정크 파일, 스팸 메일 |
| Chunk | 조각, 덩어리 | JS 코드 블록, 메모리 청크 등 |
둘은 완전히 다른 의미.
@loadable/component로 preload를 적극 활용styled-components 사용자에게 익숙하고 강력한 선택지