10

我在我的服务器端渲染应用程序中集成了材质 UI,并遵循了此处给出的代码。Material UI css 已添加到服务器端本身的 html 中。

但是,在初始加载时,没有应用材质 ui 样式,这会导致它闪烁。

我尝试<cssbaseline>与下面的代码一起使用,但没有发现任何区别。

这是我的代码:server.js

import App from '../common/containers/App';
import { Provider } from 'react-redux';
import React from 'react';
import configureStore from '../common/store/configureStore';
import express from 'express';
import qs from 'qs';
import { renderToString } from 'react-dom/server';
import serialize from 'serialize-javascript';
import { StaticRouter, matchPath } from 'react-router-dom';
import {theme} from '../theme';
import { ServerStyleSheets, ThemeProvider } from '@material-ui/styles';
import routes from './routes'
import "../common/assets/SCSS/app.scss";

const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
const server = express();
server
  .disable('x-powered-by')
  .use(express.static(process.env.RAZZLE_PUBLIC_DIR))
  .get('/*', (req, res) => {
    const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
    const promise = activeRoute.fetchInitialData
      ? activeRoute.fetchInitialData(req.path)
      : Promise.resolve()
    promise.then((apiResult) => {
      const sheets = new ServerStyleSheets();
      const counter =  apiResult || 0;
      const preloadedState = { counter };
      const store = configureStore(preloadedState);
      const context = {};
      const markup = renderToString(
         sheets.collect(
           <Provider store={store}>
            <ThemeProvider theme={theme}>
              <StaticRouter location={req.url} context={context}>
                <App />
              </StaticRouter>
            </ThemeProvider>
          </Provider>
      ));
   const css = sheets.toString();
      const finalState = store.getState();
      const html = `<!doctype html>
          <html lang="">
          <head>
              ${assets.client.css
                ? `<link rel="stylesheet" href="${assets.client.css}">`
                : ''}
                ${css ? `<style id='jss-ssr'>${css}</style>` : ''}
                ${process.env.NODE_ENV === 'production'
                  ? `<script src="${assets.client.js}" defer></script>`
                  : `<script src="${assets.client.js}" defer crossorigin></script>`}
          </head>
          <body>
              <div id="root">${markup}</div>
              <script>
                window.__PRELOADED_STATE__ = ${serialize(finalState)}
              </script>
          </body>
      </html>`
 res.send(html);
    });
  });

export default server;

客户端.js

import React,{useEffect} from 'react';
import { hydrate } from 'react-dom';
import {theme} from '../theme';
import { ThemeProvider } from '@material-ui/styles';
import { Provider } from 'react-redux';
import configureStore from '../common/store/configureStore';
import App from '../common/containers/App';
import { BrowserRouter } from "react-router-dom";
import "../common/assets/SCSS/app.scss";
import * as serviceWorker from '../serviceWorker';
import CssBaseline from '@material-ui/core/CssBaseline';

const store = configureStore(window.__PRELOADED_STATE__);
const Client = () => {
  useEffect(() => {
   
    const jssStyles = document.querySelector('#jss-ssr');
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return(
    <Provider store={store}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </ThemeProvider>
    </Provider>
  );

}


hydrate(<Client />,document.getElementById('root'));
4

1 回答 1

1

这是由于您的客户端代码在生成客户端样式之前删除了服务器生成的样式。

提供的hydra函数react-dom有第三个参数,它是一个回调函数,在应用程序的 hydration 完成后调用。

此回调函数应用于确保应用程序已完成水合并已生成客户端样式。

import React,{useEffect} from 'react';
import { hydrate } from 'react-dom';
import {theme} from '../theme';
import { ThemeProvider } from '@material-ui/styles';
import { Provider } from 'react-redux';
import configureStore from '../common/store/configureStore';
import App from '../common/containers/App';
import { BrowserRouter } from "react-router-dom";
import "../common/assets/SCSS/app.scss";
import * as serviceWorker from '../serviceWorker';
import CssBaseline from '@material-ui/core/CssBaseline';

const store = configureStore(window.__PRELOADED_STATE__);

const Client = () => {
  return(
    <Provider store={store}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </ThemeProvider>
    </Provider>
  );

}


hydrate(
    <Client />,
    document.getElementById('root'),
    () => {
        const jssStyles = document.querySelector('#jss-ssr');

        if (jssStyles) {
            jssStyles.parentElement.removeChild(jssStyles);
        }
    }
);
于 2020-10-27T02:02:18.863 回答