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

时间:2018-07-19 23:46:12

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

我不知道我的问题是 bug 还是仅仅是 support 术语,还是仅仅是 configuration 错误,但是我花了很多时间,不高兴去这里幸运地写给别人解决我的问题。不!

我搜索了3天,即使在这3天内仅睡了大约10个小时,还是尝试了多种方法,甚至我使用了Gitter,但没人回答我,我看到了问题#10982和{{3 }}和许多Stack Overflow问题和答案,但我无法解决自己的问题,也找不到正确的方法。

当然,我读过Material-UI #11506多次,但我完全按照文档所说的去做。

最后,我在服务器和客户端中看到类名水化不匹配,这是警告:

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-UI1.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包裹在其中?< / em>

因此,首先请参见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,我想也许这个功能应该包装一些东西。所以我尝试了多种形状,而且效果很好。但是在构建后在浏览器中的第一个调用中。当我刷新浏览器时,警告出现,并且我看到该死的形状:

image

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

image

我不知道怎么了。我也在Docs上留下了一个问题。并为此问题上载Github,仅查看pull,然后先运行npm install然后运行num run dev。该项目可以在mini repo

上访问

1 个答案:

答案 0 :(得分:0)

我不知道这种方法是否正确,但是它很好用,实际上,我发现使用单独的rtl.jsx组件不是一个好方法,这导致服务器和客户端之间的不一致,我分别为每个服务器端和客户端使用Right-to-Left文档页面,因此从我的项目中省略了server.jsx文件及其组件,所以client.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: markup, helmet: helmet, jss: jss, })); }; } 就像下方:

Material-UI

它在服务器和客户端上都可以很好地工作,并且在样式标签中使CSS {{1}}保持一致。