React Material-ui SSR - 警告:道具“d”不匹配。服务器:"M 0 0 h 24 v 24 H 0 Z" 客户端:"M0 0h24v24H0z"

React Material-ui SSR - Warning: Prop `d` did not match. Server: "M 0 0 h 24 v 24 H 0 Z" Client: "M0 0h24v24H0z"

我正在使用服务器端呈现和 Material-ui 开发 React 站点。一切都很好,包括 mui JSS 东西。

然后我从@material-ui/icons

添加了一个SVG图标

现在,Edge 和 IE11 正在抱怨: 警告:道具 d 不匹配。服务器:"M 0 0 h 24 v 24 H 0 Z" 客户端:"M0 0h24v24H0z"

警告表明服务器和客户端渲染不匹配,但如果我使用 curl 获得服务器渲染,它是正确的并且不包括 IE/Edge 控制台中显示的空格。

所有其他浏览器(当然)都可以。

有没有其他人仅在 MS 浏览器中遇到过 SSR 问题?

这是我能得到的最小示例。它基于 material-ui-master/examples/ssr 并删除了大部分内容:

server.js:

import express from "express";
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';

function renderFullPage(html) {
  return `
    <!doctype html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="build/bundle.js"></script>
      </body>
    </html>
  `;
}

function handleRender(req, res) {
  // Render the component to a string.
  const html = ReactDOMServer.renderToString(
        <App />
  );

  res.send(renderFullPage(html));
}

const app = express();

app.use('/build', express.static('build'));

// This is fired every time the server-side receives a request.
app.use(handleRender);

const port = 3000;
app.listen(port);

client.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

class Main extends React.Component {
  render() {
    return <App />;
  }
}

ReactDOM.hydrate(
  <Main />
  , document.querySelector('#root')
);

App.js:

import React from 'react';
import { Menu } from "@material-ui/icons";

export default class App extends React.Component {
  render() {
    return (
      <Menu />
    );
  }
}

package.json:

{
  "name": "ssr",
  "version": "3.0.0",
  "private": true,
  "dependencies": {
    "@babel/core": "latest",
    "@babel/node": "latest",
    "@babel/plugin-proposal-class-properties": "latest",
    "@babel/preset-env": "^7.4.2",
    "@babel/preset-react": "latest",
    "@material-ui/core": "latest",
    "@material-ui/icons": "^3.0.2",
    "babel-loader": "next",
    "express": "latest",
    "fs": "0.0.1-security",
    "net": "^1.0.2",
    "nodemon": "latest",
    "prop-types": "latest",
    "react": "latest",
    "react-dom": "latest",
    "react-jss": "^8.1.0",
    "webpack": "latest",
    "webpack-cli": "latest"
  },
  "scripts": {
    "start-server": "SET NODE_ENV=development& nodemon --inspect ./build/server.js",
    "start": "webpack -w"
  }
}

webpack.config.js:

const path = require('path');

const browserConfig = {
  entry: './client.js',
  node: {
    fs: "empty"
  },
  mode: process.env.NODE_ENV || 'development',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js',
    publicPath: '/',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
    ],
  },
};

const serverConfig = {
  entry: './server.js',
  target: 'node',
  node: {
    fs: "empty"
  },
  mode: process.env.NODE_ENV || 'development',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'server.js',
    publicPath: '/',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
    ],
  },
};

module.exports = [browserConfig, serverConfig]

.babel.rc:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

我遇到了类似的问题。这不是 SSR 的问题,而是 JSX 中条件渲染的问题,其中服务器和客户端的条件不同。

在我的例子中,我根据从 localStorage 读取的条件渲染了一些内容,该条件仅在客户端定义。在服务器上,它返回 undefined,因此在客户端和服务器上呈现的内容不匹配。

我的解决方案是根据组件是否在客户端呈现来有条件地呈现。

我编写了以下自定义挂钩:

import {useEffect, useState} from "react";

export const useLoaded = () => {
    const [loaded, setLoaded] = useState(false);
    useEffect(() => setLoaded(true), []);
    return loaded;
};

我是这样用的:

// in the functional component's body
const loaded = useLoaded();

// in the JSX
{localCondition && loaded &&
  <MyComponent />
}

对于 class 个组件,您将使用 componentDidMount 生命周期方法,而不是 setState

所以这看起来确实是 React 中的一个错误。我在 Material-ui 项目中记录了一个问题,该问题在 React 中导致了这个未解决的问题:

https://github.com/facebook/react/issues/15187

这个警告似乎是良性的,并且随着 Edge 转向 Chromium,我不再像以前那样担心了。

我遇到了同样的问题 ...不匹配服务器:...客户端:... 使用带有 Express.js 的 NextJS (React)服务器(节点server.js)。

解决方案是仅在 process.browsertrue 时渲染组件。

{
  process.browser ?
  <MyComponent /> :
  null
}