繁体   English   中英

服务器和客户端中的类名水化不匹配,(警告:Prop `className` 与服务器和客户端不匹配)

[英]Class name hydration mismatch in server and client, (Warning: Prop `className` did not match Server and Client)

我不知道我的问题是一个错误,或者只是一个支持条款,或者只是一个配置错误,但我花了很多时间,不高兴去幸运地写到这里来解决我的问题。 不!

我搜索了 3 天,这 3 天甚至只睡了大约 10 个小时,尝试了很多方法,即使我使用Gitter但没有人回答我,我看到问题#10982#11506以及许多Stack Overflow问题和答案,但我不能' t 解决了我的问题,但没有找到正确的方法。

我绝对阅读了很多次Material-UI Docs,但我完全按照 Docs 所说的去做。

最后,我在服务器和客户端看到类名 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>`;
};

好的,现在有可能会问这个问题What is 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-UI Docs 中看到了它,我相信文档有点差,可以改进。 我问自己,为什么文档props.children为这个函数传递一个props.children 我想也许这个函数应该包装一些东西。 所以我尝试了许多形状并且它有效。 但是在构建后在浏览器中的第一次调用中。 当我刷新浏览器时会出现警告😞,我看到了这个该死的形状:

图片

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

图片

我不知道出了什么问题。 我也在Github上留下了一个问题。 并为此问题上传一个迷你存储库,以便查看我的问题,只需pull ,然后运行npm install然后num run dev 该项目可在localhost:4000上访问

我不知道这种方式是否合适,但效果很好,实际上,我发现使用单独的RTL Component并不是一个好方法,这导致服务器和客户端之间的不一致,我使用了Right-to -为每个服务器和客户端分别Rtl.jsx文档页面,因此省略了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-UI CSS

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM