
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;
}
}
`;