【问题标题】:Class name hydration mismatch in server and client, (Warning: Prop `className` did not match Server and Client)服务器和客户端中的类名水合不匹配,(警告:Prop `className` 与服务器和客户端不匹配)
【发布时间】:2018-12-28 05:08:12
【问题描述】:

我不知道我的问题是 错误 或只是 支持 术语或只是 配置 不匹配,但我花了很多时间, 不高兴去幸运写在这里有人解决我的问题。不!

我搜索了 3 天,即使在这 3 天内只睡了大约 10 个小时,尝试了很多方法,即使我使用 Gitter 但没有人回答我,我看到问题 #10982#11506 和许多 @987654331 @问题和答案,但我无法解决我的问题,也没有找到正确的方法。

当然,我读了很多遍Material-UIDocs,但我完全按照文档所说的做了。

最后,我看到服务器和客户端的类名 hydration 不匹配,????这个警告:

Warning: Prop `className` did not match. Server: "MuiFormLabel-root-134 MuiInputLabel-root-129 MuiInputLabel-formControl-130 MuiInputLabel-animated-133" Client: "MuiFormLabel-root-10 MuiInputLabel-root-5 MuiInputLabel-formControl-6 MuiInputLabel-animated-9"

我发誓我尝试了很多方法并进行了很多搜索。我正在使用Material-UI 版本1.2.1

这是我作为根组件的Index 组件:

import React, {Component} from 'react';
import Helmet from 'react-helmet';
import styles from 'StylesRoot/styles.pcss';
import TextField from '@material-ui/core/TextField';

export default class App extends Component {

    render() {
        return (
            <div className={styles['root-wrapper']}>
                <Helmet
                    htmlAttributes={{lang: 'fa', amp: undefined}}
                    bodyAttributes={{dir: 'rtl'}}
                    titleTemplate='اسکن - %s'
                    titleAttributes={{itemprop: 'name', lang: 'fa'}}
                    meta={[
                        {name: 'description', content: 'صفحه اتصال اعضاء'},
                        {name: 'viewport', content: 'width=device-width, initial-scale=1'},
                    ]}
                    link={[{rel: 'stylesheet', href: '/dist/styles.css'}]}
                />
                <TextField label='test' helperText='help'/>
            </div>
        );
    };
}

在下面你可以看到我的server.jsxclient.jsx

//--------------------------------------------client.jsx
import React from 'react';
import {hydrate} from 'react-dom';
import {BrowserRouter} from 'react-router-dom';
import {MuiThemeProvider, createMuiTheme} from '@material-ui/core/styles';
import {lightBlue, red} from '@material-ui/core/colors';
import Index from './app/index';
import RTL from './app/public/rtl';

const theme = createMuiTheme({
    palette: {
        primary: lightBlue,
        accent: red,
        type: 'light',
    },
    direction: 'rtl',
});

class Main extends React.Component {
    // Remove the server-side injected CSS.
    componentDidMount() {
        const jssStyles = document.getElementById('jss-server-side');
        if (jssStyles && jssStyles.parentNode) {
            jssStyles.parentNode.removeChild(jssStyles);
        }
    }

    render() {
        return (
            <BrowserRouter>
                <Index {...this.props}/>
            </BrowserRouter>
        );
    }
}

hydrate((
    <RTL>
        <MuiThemeProvider theme={theme}>
            <Main/>
        </MuiThemeProvider>
    </RTL>
), document.getElementById('root'));



//--------------------------------------------server.jsx
import React from 'react';
import {renderToString} from 'react-dom/server';
import {SheetsRegistry} from 'react-jss/lib/jss';
import JssProvider from 'react-jss/lib/JssProvider';
import {StaticRouter} from 'react-router-dom';
import {Helmet} from "react-helmet";
import {MuiThemeProvider, createMuiTheme, createGenerateClassName} from '@material-ui/core/styles';
import {red, lightBlue} from '@material-ui/core/colors';
import Template from './app/template';
import Index from './app/index';
import RTL from './app/public/rtl';

export default function serverRenderer({clientStats, serverStats}) {
    return (req, res, next) => {
        const context = {};
        const sheetsRegistry = new SheetsRegistry();
        const theme = createMuiTheme({
            palette: {
                primary: lightBlue,
                accent: red,
                type: 'light',
            },
            direction: 'rtl',
        });
        const generateClassName = createGenerateClassName();
        const markup = renderToString(
            <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}>
                <RTL>
                    <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
                        <StaticRouter location={req.url} context={context}>
                            <Index/>
                        </StaticRouter>
                    </MuiThemeProvider>
                </RTL>
            </JssProvider>
        );
        const helmet = Helmet.renderStatic();

        const jss = sheetsRegistry.toString();

        res.status(200).send(Template({
            markup: markup,
            helmet: helmet,
            jss: jss,
        }));
    };
}

所以现在需要template.jsx:

export default ({ markup, helmet, jss }) => {
    return `<!DOCTYPE html>
            <html ${helmet.htmlAttributes.toString()}>
                <head>
                    ${helmet.title.toString()}
                    ${helmet.meta.toString()}                   
                    ${helmet.link.toString()}
                    <style id='jss-server-side'>${jss}</style>                                  
                </head>
                <body ${helmet.bodyAttributes.toString()}>
                    <div id='root'>${markup}</div>
                    <script src='/dist/client.js' async></script>
                </body>
            </html>`;
};

好的,现在可能会问这个问题RTL 是什么? 以及 为什么你在服务器和客户端都将MuiThemeProvider 包裹在其中?

所以先看RTL组件:

import React from 'react';
import {create} from 'jss';
import rtl from 'jss-rtl';
import JssProvider from 'react-jss/lib/JssProvider';
import {createGenerateClassName, jssPreset} from '@material-ui/core/styles';

const jss = create({plugins: [...jssPreset().plugins, rtl()]});

const generateClassName = createGenerateClassName();

export default props => (
    <JssProvider jss={jss} generateClassName={generateClassName}>
        {props.children}
    </JssProvider>
);

我在Material-UIDocs 看到了它,我相信文档有点差,可以改进。我问自己,为什么文档会为这个函数传递一个props.children 我猜这个函数可能应该包含一些东西。所以我尝试了很多形状,它的工作原理。但在构建后第一次调用浏览器时。当我刷新浏览器然后出现警告????我看到了这个该死的形状:

我当然想看看下面的形状,但我只在构建后看到过一次:

我不知道出了什么问题。我也在Github 上留下了一个问题。并为此问题上传mini repo,以查看我的问题pull,然后运行npm install,然后运行num run dev。该项目可通过localhost:4000访问

【问题讨论】:

    标签: javascript reactjs material-ui right-to-left


    【解决方案1】:

    我不知道这种方式是否合适,但是效果很好,实际上我发现,使用单独的RTL组件,不是一个好方法,这导致服务器和客户端之间的不一致,我分别为每个服务器和客户端使用Right-to-Left 文档页面,因此省略了Rtl.jsx 文件,它是我项目中的组件,所以server.jsxclient.jsx 如下所示:

    //---------------------------------------------client.jsx
    import React, {Component} from 'react';
    import {hydrate} from 'react-dom';
    import {BrowserRouter} from 'react-router-dom';
    import {
        MuiThemeProvider, createMuiTheme,
        createGenerateClassName, jssPreset
    } from '@material-ui/core/styles';
    import {create} from 'jss';
    import rtl from 'jss-rtl';
    import JssProvider from 'react-jss/lib/JssProvider';
    import {lightBlue, red} from '@material-ui/core/colors';
    import Index from './app/index';
    
    const theme = createMuiTheme({
        palette: {
            primary: lightBlue,
            accent: red,
            type: 'light',
        },
        direction: 'rtl',
    });
    
    const jssRTL = create({plugins: [...jssPreset().plugins, rtl()]});
    
    const generateClassName = createGenerateClassName();
    
    class Main extends Component {
        componentDidMount() {
            const jssStyles = document.getElementById('jss-server-side');
            if (jssStyles) {
                jssStyles.remove();
            }
        }
    
        render() {
            return (
                <BrowserRouter>
                    <Index {...this.props}/>
                </BrowserRouter>
            );
        }
    }
    
    hydrate((
        <JssProvider jss={jssRTL} generateClassName={generateClassName}>
            <MuiThemeProvider theme={theme}>
                <Main/>
            </MuiThemeProvider>
        </JssProvider>
    ), document.getElementById('root'));
    
    
    //---------------------------------------------server.jsx
    import React from 'react';
    import {renderToString} from 'react-dom/server';
    import {SheetsRegistry} from 'react-jss/lib/jss';
    import JssProvider from 'react-jss/lib/JssProvider';
    import {StaticRouter} from 'react-router-dom';
    import {Helmet} from "react-helmet";
    import {
        MuiThemeProvider, createMuiTheme,
        createGenerateClassName, jssPreset
    } from '@material-ui/core/styles';
    import {create} from 'jss';
    import rtl from 'jss-rtl';
    import {red, lightBlue} from '@material-ui/core/colors';
    import Template from './app/template';
    import Index from './app/index';
    
    export default function serverRenderer({clientStats, serverStats}) {
        return (req, res, next) => {
    
            const context = {};
    
            const sheetsRegistry = new SheetsRegistry();
    
            const theme = createMuiTheme({
                palette: {
                    primary: lightBlue,
                    accent: red,
                    type: 'light',
                },
                direction: 'rtl',
            });
    
            const jssRTL = create({plugins: [...jssPreset().plugins, rtl()]});
    
            const generateClassName = createGenerateClassName();
    
            const markup = renderToString(
                <JssProvider jss={jssRTL}
                             registry={sheetsRegistry}
                             generateClassName={generateClassName}>
                    <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
                        <StaticRouter location={req.url} context={context}>
                            <Index pathname={req.url}/>
                        </StaticRouter>
                    </MuiThemeProvider>
                </JssProvider>
            );
            const helmet = Helmet.renderStatic();
    
            const jss = sheetsRegistry.toString();
    
            res.status(200).send(Template({
                markup,
                helmet,
                jss,
            }));
        };
    }
    

    它在双方、服务器和客户端都运行良好,并且在样式标记中保持一致的Material-UICSS

    【讨论】:

      最近更新 更多