ReactでUIコンポーネントを使う時にMaterial-UIは一番有力な選択肢だと思います。
Next.jsでも同じように使いたいところですが、サーバーサイドレンダリング(SSR)時にcss modulesによるクラス名付与が合わなくなる問題が起きました。
index.js:1 Warning: Prop className
did not match. Server: "MuiBox-root...
これによって一部スタイルが崩れてしまう。
dev
での再コンパイルや内部遷移によって直ることもあるがproduction
でも問題が起きるので使い物にならない状態なので対策します。
対策方法ですがMaterialUIのSSRが用意されています。
これをNext.jsに取り入れるために_documsnt.jsをカスタムします。
Material iconsと<Typography>
のためのRobotoの読み込みもついでに。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
import Document, { Html, Head, Main, NextScript } from "next/document"; import { ServerStyleSheets } from "@material-ui/styles"; class MyDocument extends Document { static async getInitialProps(ctx) { const sheet = new ServerStyleSheets(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: App => props => sheet.collect(<App {...props} />) }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ) }; } finally { ctx.renderPage(sheet); } } render() { return ( <Html> <Head> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); } } export default MyDocument; |
これでWarningは消え正しく表示されるようになりました。
一息ついたところですがreact-custom-scrollbarsを導入したところ、同様のエラーが出ました。
これはuniversal
プロパティを付けるだけで解決しましたが、コンポーネントライブラリを追加するとまた出てきそうな感じがします。
調べつつ色々とconfigをいじったりもしましたが根本解決はできなかったので、現状ではライブラリ側でSSR適応されていることを期待するしかないです。問題が起きたら再度取り組むか。
Tips
nextの中にこんなのがありました。:next-plugin-material-ui
ソースを見ると今回のコードと同様の感じですね。
現在は実験的だからまだ使うなという状態ですが、そのうち使えるようになるかも。
こんなのがあるあたりMaterial UIはnext.jsで何か作るときのデファクトスタンダードだと思ってもよさそうな感じです。
追記:Examples in material ui
Material UI側にもnext.jsを使うサンプルがありました。こっちの方がわかりやすい。
この記事を見て、解決することができました!
ありがとうございます!