# next.js에서 material-ui와 styled-components 사용하기
이번에는 이전 next.js에서 material-ui 사용하기 (opens new window) 글에 이어서 mui와 styled-components를 같이 사용하는 방법에 대해 알아보겠습니다.
혹시 이 글을 처음 보시는 분이라면 next.js에서 material-ui 사용하기 (opens new window) 이 글을 참조하셔서 nextJS 부터 mui 세팅까지 하고 오시기를 권고드립니다!
mui v5 버전 기준으로 작성하였습니다. 이전 버전은 작동하지 않을 수 있습니다.
# 프로젝트 세팅
- 먼저 예시에 필요한 디펜던시를 설치합니다.
yarn add -D babel-plugin-styled-components
Copied!
# .babelrc
- 먼저 바벨 파일을 수정합니다.
- 아래 파일은 next.js의 ssr과 연관이 있는데, ssr에 의해 styled-components 스타일이 적용 전에 화면 렌더링이 되는 문제를 방지하기 위함입니다.
{ "presets": ["next/babel"], "plugins": [ [ "babel-plugin-styled-components", { "fileName": true, "displayName": true, "pure": true, "ssr": true } ] ] }
Copied!
# _document.tsx
- babel 설정 파일을 설정했다면 이제
_document
파일을 설정합니다. (아직 styled-components가 서버렌더링에 세팅되지 않음) - mui가 nextjs에서 작동하도록 설정하였는데 그 위에 styled-components도 사용 하도록 설정합니다.
import React from "react"; import Document, { Html, Head, Main, NextScript } from "next/document"; import { ServerStyleSheet } from "styled-components"; import { ServerStyleSheets } from "@mui/styles"; export default class MyDocument extends Document { render() { return ( <Html> <Head /> <body> <Main /> <NextScript /> </body> </Html> ); } } MyDocument.getInitialProps = async ctx => { const sheet = new ServerStyleSheet(); const materialSheets = new ServerStyleSheets(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: App => props => sheet.collectStyles(materialSheets.collect(<App {...props} />)) }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ) }; } finally { sheet.seal(); } };
Copied!
# 설명
ServerStyleSheet
를 이용하여materialSheets
라는 인스턴스를 생성합니다.materialSheets
를 이용하여 지정한 컴포넌트(ex:<App />
)의 스타일 요소를 검색하고 그 스타일을<style>
태그로 추출합니다.- 추출한 결과물을
Document
에 전달합니다. - 이렇게 되면 서버에서 렌더링되고 소스 페이지에서도 스타일이 표시됩니다.
# _app.tsx
- ThemeProvider를 주입하고 theme를 사용하도록 세팅합니다.
import type { AppProps } from "next/app"; import CssBaseline from "@mui/material/CssBaseline"; import { ThemeProvider } from 'styled-components' const theme = { primary: 'green', } const App = (props: AppProps) => { const { Component, pageProps } = props; return ( <ThemeProvider theme={theme}> <CssBaseline /> <Component {...pageProps} /> </ThemeProvider> ); }; export default App;
Copied!
# 글로벌 스타일 사용하기
styled-components
에서 글로벌 스타일을 사용하는 예시입니다
# styles/global-styles.ts
- 먼저 글로벌 스타일을 정의합니다.
// styles/global-styles.ts import { createGlobalStyle } from "styled-components"; export const GlobalStyle = createGlobalStyle` html, body { padding: 0; margin: 0; letter-spacing: -1px; font-size: 15px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } .txt-c { text-align: center; } .txt-r { text-align: right; } .txt-l { text-align: left; } p { margin: 0; } `;
Copied!
# _app.tsx
_app.tsx
에 사용한 글로벌 스타일을 넣어줍니다.
import type { AppProps } from "next/app"; import CssBaseline from "@mui/material/CssBaseline"; import { ThemeProvider } from 'styled-components' import { GlobalStyle } from "styles/global-styles"; const theme = { primary: 'green', } const App = (props: AppProps) => { const { Component, pageProps } = props; return ( <ThemeProvider theme={theme}> <GlobalStyle /> <CssBaseline /> <Component {...pageProps} /> </ThemeProvider> ); }; export default App;
Copied!