Next와 ts에서 styled-components 를 사용할 때 추가적으로 설정해주어야하는 것들이 존재해서 포스팅을 해본다!
기존 Next와 ts를 초기세팅한뒤 보통 styled-components 설정을 해준다.
아래에 명령어로 Next에 styled-components를 사용하기 위해 필요한 라이브러리들을 설치합니다
npm install styled-components
npm install @types/styled-components
_document.tsx
는 pages
폴더 내부에 존재하는 모든 페이지에 global한 설정 값을 줄 수 있는 파일입니다.
여기서 style을 불러와서 주입해주는 것이죠. 저는 index.html 의 역할을 한다고 이해하고 있습니다. styled-component 뿐만 아니라 다른 값들도 넣어줄 수 있습니다.
<>
<link
rel="stylesheet"
type="text/css"
href="static/css/reset.css"
/>
{initialProps.styles}
{sheet.getStyleElement()}
</>
이렇게 다른 css 파일도 넣어줄 수 있습니다.
본론으로 돌아와 Next, styled-components에서 _document
설정을 해주는 이유는 Next에서는 초기에 SSR
을 사용하게되는데 SSR
을 하면서 문제가 생겼습니다. css 파일이 나중에 적용되면서 화면이 깜박거리는 현상이 있었습니다. css가 입혀지기 전에 html 파일이 그대로 노출이되는 거였죠.
간단하게 CSS가 적용되지 않고 먼저 렌더링되는 현상이 발생한다.
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
} from "next/document";
import { ServerStyleSheet } from "styled-components";
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
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();
}
}
render() {
return (
<Html>
<Head>
// 생략
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
그래서 해당 코드를 추가해주어야 SSR시에 styled가 헤더에 주입됩니다.
넥스트는 최초 ssr이후 내부 라우팅을 통해 페이지가 이동되면서 csr을 하게되는데 이때, 서버에서 생성하는 해시값과 브라우저에서 생성하는 해시값이 서로 달라서 문제가 발생하게 됩니다.
<Prop className did not match. 에러 발생 >
해결을 위해 설치
npm install babel-plugin-styled-components
{
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-styled-components",
{ "fileName": true, "displayName": true, "pure": true, "ssr": true }
]
]
}
해당 코드를 추가
마지막으로 globalstyle을 추가해준다.
import { createGlobalStyle } from "styled-components";
import { reset } from "styled-reset";
import { media } from "./theme";
export const GlobalStyle = createGlobalStyle`
${reset}
:focus {
outline: none;
border: none;
}
::-webkit-scrollbar {
display: none;
}
html{
font-size: 11px;
-webkit-text-size-adjust: none;
font-family: -apple-system,BlinkMacSystemFont,helvetica,Apple SD Gothic Neo,sans-serif;
font-display: fallback;
${media.tablet}{
font-size: 10px;
}
-ms-overflow-style: none;
scrollbar-width: none;
}
button {
background: none;
padding: 0;
border: none;
cursor: pointer;
&:disabled {
cursor: default;
fill: #f2f3f4;
}
}
.pc-tablet-only {
display: block;
${media.mobile} {
display: none;
}
}
.tablet-mobile-only{
display: none;
${media.tablet}{
display:block;
}
}
.mobile-only {
display: none;
${media.mobile} {
display: block;
}
}
`;