Next.js13 + styled-components_에러 및 해결
에러 상황
에러 설명을 읽어보니 서버와 클라이언트의 클래스명이 다르다고 나왔다.
검색을 해보니 Next.js에서 styled-components를 사용하면 위와 같은 경고가 뜨곤 한다고 했다.
원인
그렇다면 next에서 스타일 적용 시, 왜 이런 에러가 발생할까?
Next.js는 첫 페이지 로드가 SSR로 동작하기 때문에, 서버에서 생성된 컴포넌트와 CSR로 클라이언트에서 생성된 컴포넌트의 클래스명이 서로 달라지게 된다.
해결 방법은 두 가지가 있는데, 아래 두가지 방법 중 하나로 해결하면 된다. 만일 사용중인 Next.js가 최신 버전이라면 두번째 방법을 사용하는 것을 추천한다.
- 두 가지 방법을 동시에 적용하면 바벨이 충돌나서 제대로 작동하지 않는다.
해결 방법
방법 1. babel-plugin-styled-components
환경에 따라 달라지는 className을 일관되게 해주는 것이 바로 babel-plugin-styled-components이다.
1. 설치
1
$ npm I –D babel-plugin-styled-components
2. babelrc 설정
프로젝트 루트에 .babelrc를 생성한 뒤 설정을 추가하고, 서버를 재실행한다.
1
2
3
4
5
6
7
8
9
10
11
12
// .babelrc
{
"presets": ["next/babel"], // -> 이거 설정안하면 빌드안됨
"plugins": [
[
"babel-plugin-styled-components",
{
"ssr": false
}
]
]
}
3. _document.tsx
Next.js에서 styled-components를 사용할 때 _document를 따로 설정해서 SSR될 때 CSS가 head에 주입되도록 해야 한다. 만약 따로 설정하지 않는다면, styled-components가 적용되지 않은 상태로 렌더링될 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// pages/_document.tsx
import Document, { DocumentContext, DocumentInitialProps } from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />)
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: [
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
]
};
} finally {
sheet.seal();
}
}
}
방법 2. next.config.js 옵션 설정
Next.js 최신 버전에서는 styled-components의 ssr를 잘 지원해주므로, Next.js의 컴파일러 옵션만으로 간단하게 해결할 수 있다.
1
2
3
4
5
6
7
// next.config.js
module.exports = {
compiler: {
// ssr and displayName are configured by default
styledComponents: true
}
};
📑 참고 자료
[Next.js] Next.js에서 Prop className
did not match 경고가 뜨는 이유
(Next.js + styled-components) Props classname did not match
에러 및 해결
[classpick 개발일지 #1] Next.js13으로 마이그레이션하기 - emotion 써도 되나? 고민하기