Первое предостережение - в настоящее время я сам не имею опыта использования SSR, но у меня есть глубокое знание Material-UI , и я думаю, что с кодом, который вы включили в свой вопрос и Next . js документация, я могу помочь вам в этом.
Вы уже показываете в своем _app.js
, как вы устанавливаете theme
в свои стилевые компоненты ThemeProvider
. Вам также нужно будет установить тему для Material-UI ThemeProvider, и вам нужно будет выбрать одну из двух возможных тем в зависимости от типа устройства.
Сначала определите две темы, которые вас интересуют. В двух темах будут использоваться различные реализации ssrMatchMedia
- одна для мобильных устройств, а другая для настольных компьютеров.
import mediaQuery from 'css-mediaquery';
import { createMuiTheme } from "@material-ui/core/styles";
const mobileSsrMatchMedia = query => ({
matches: mediaQuery.match(query, {
// The estimated CSS width of the browser.
width: "0px"
})
});
const desktopSsrMatchMedia = query => ({
matches: mediaQuery.match(query, {
// The estimated CSS width of the browser.
width: "1024px"
})
});
const mobileMuiTheme = createMuiTheme({
props: {
// Change the default options of useMediaQuery
MuiUseMediaQuery: { ssrMatchMedia: mobileSsrMatchMedia }
}
});
const desktopMuiTheme = createMuiTheme({
props: {
// Change the default options of useMediaQuery
MuiUseMediaQuery: { ssrMatchMedia: desktopSsrMatchMedia }
}
});
Чтобы выбрать одну из двух тем, вам нужно использовать пользовательский агент из запроса. , Здесь мои знания очень легки, поэтому в моем коде могут быть незначительные проблемы. Я думаю, вам нужно использовать getInitialProps
(или getServerSideProps
в Next. js 9.3 или новее). getInitialProps
получает объект контекста , из которого можно получить объект запроса HTTP (req
). Затем вы можете использовать req
таким же образом, как в примере документации Material-UI, чтобы определить тип устройства.
Ниже приведено приблизительное значение того, как я думаю, _app.js
должно выглядеть (не выполнено, поэтому может иметь незначительные проблемы с синтаксисом и некоторые предположения в getInitialProps
, так как я никогда не использовал Next. js):
import NextApp from "next/app";
import React from "react";
import { ThemeProvider } from "styled-components";
import { createMuiTheme, MuiThemeProvider } from "@material-ui/core/styles";
import mediaQuery from "css-mediaquery";
import parser from "ua-parser-js";
const theme = {
primary: "#4285F4"
};
const mobileSsrMatchMedia = query => ({
matches: mediaQuery.match(query, {
// The estimated CSS width of the browser.
width: "0px"
})
});
const desktopSsrMatchMedia = query => ({
matches: mediaQuery.match(query, {
// The estimated CSS width of the browser.
width: "1024px"
})
});
const mobileMuiTheme = createMuiTheme({
props: {
// Change the default options of useMediaQuery
MuiUseMediaQuery: { ssrMatchMedia: mobileSsrMatchMedia }
}
});
const desktopMuiTheme = createMuiTheme({
props: {
// Change the default options of useMediaQuery
MuiUseMediaQuery: { ssrMatchMedia: desktopSsrMatchMedia }
}
});
export default class App extends NextApp {
static async getInitialProps(ctx) {
// I'm guessing on this line based on your _document.js example
const initialProps = await NextApp.getInitialProps(ctx);
// OP's edit: The ctx that we really want is inside the function parameter "ctx"
const deviceType =
parser(ctx.ctx.req.headers["user-agent"]).device.type || "desktop";
// I'm guessing on the pageProps key here based on a couple examples
return { pageProps: { ...initialProps, deviceType } };
}
componentDidMount() {
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles && jssStyles.parentNode)
jssStyles.parentNode.removeChild(jssStyles);
}
render() {
const { Component, pageProps } = this.props;
return (
<MuiThemeProvider
theme={
pageProps.deviceType === "mobile" ? mobileMuiTheme : desktopMuiTheme
}
>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
<style jsx global>
{`
body {
margin: 0;
}
.tui-toolbar-icons {
background: url(${require("~/public/tui-editor-icons.png")});
background-size: 218px 188px;
display: inline-block;
}
`}
</style>
</ThemeProvider>
</MuiThemeProvider>
);
}
}