简体   繁体   English

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

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

I don't know my issue is a bug or just a support term or just a configuration mismach, but I spend much time, Not happy go lucky writing here to somebody settle my issue.我不知道我的问题是一个错误,或者只是一个支持条款,或者只是一个配置错误,但我花了很多时间,不高兴去幸运地写到这里来解决我的问题。 no!不!

I searched for 3 days, Even just sleep about 10 hours in this 3 days, try many ways, even I use Gitter but no one answer me, I see issues #10982 and #11506 and many Stack Overflow question and answers but I couldn't fix my issue and didn't find right way.我搜索了 3 天,这 3 天甚至只睡了大约 10 个小时,尝试了很多方法,即使我使用Gitter但没有人回答我,我看到问题#10982#11506以及许多Stack Overflow问题和答案,但我不能' t 解决了我的问题,但没有找到正确的方法。

Absolutely I read and read many times the Material-UI Docs but I exactly did what the Docs said.我绝对阅读了很多次Material-UI Docs,但我完全按照 Docs 所说的去做。

At last, I see class name hydration mismatch in server and client, 😞 this warning:最后,我在服务器和客户端看到类名 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"

I swear I tried many ways and searched a lot.我发誓我尝试了很多方法并搜索了很多。 I'm using Material-UI version 1.2.1 .我正在使用Material-UI版本1.2.1

This is my Index component as a root component:这是我作为根组件的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>
        );
    };
}

Here below you can see my server.jsx and client.jsx :在下面你可以看到我的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,
        }));
    };
}

So now it's needed to template.jsx :所以现在需要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>`;
};

Ok, Now it is possible that this question is asked What is RTL ?好的,现在有可能会问这个问题What is RTL and Why you wrap MuiThemeProvider inside it in both server and client?为什么你在服务器和客户端都将MuiThemeProvider包裹在里面?

So first see RTL component:所以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>
);

I saw it in Material-UI Docs and I believe the documentation is a little poor and could be improved.我在Material-UI Docs 中看到了它,我相信文档有点差,可以改进。 I asked myself, Why documentation pass a props.children for this function?我问自己,为什么文档props.children为这个函数传递一个props.children and I guess maybe this function should wrap something.我想也许这个函数应该包装一些东西。 so I try many shapes and it works.所以我尝试了许多形状并且它有效。 but in the first call in browser after build.但是在构建后在浏览器中的第一次调用中。 when I refresh the browser then the warning appears 😞 and I see this damn shape:当我刷新浏览器时会出现警告😞,我看到了这个该死的形状:

图片

Surely I wanna see below shape, but I see it just once after build:我当然想看到下面的形状,但我在构建后只看到一次:

图片

I don't know what is going wrong.我不知道出了什么问题。 I leave an issue on Github too.我也在Github上留下了一个问题。 And upload a mini repo for this issue, for seeing my issue just pull , and run npm install then num run dev .并为此问题上传一个迷你存储库,以便查看我的问题,只需pull ,然后运行npm install然后num run dev the project is accessible on localhost:4000该项目可在localhost:4000上访问

I don't know this way is proper or not, But it works well, Actually, I find out, using separate RTL Component, is not a good way, This cause to the inconsistency between server and client, I use the Right-to-Left Documentation page for each server and client-side separately, Hence omit the Rtl.jsx file and it's component from my project, So, server.jsx and client.jsx is like below:我不知道这种方式是否合适,但效果很好,实际上,我发现使用单独的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,
        }));
    };
}

It works well on both sides, server, and client and makes consistent Material-UI CSS in style tag.它在双方、服务器和客户端都能很好地工作,并在样式标签中制作一致的Material-UI CSS

暂无
暂无

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

相关问题 nextjs:警告:道具 `className` 不匹配。 服务器:“x” 客户端:“y” - nextjs: Warning: Prop `className` did not match. Server: "x" Client: "y" Next.Js 带有样式组件的 React 应用程序。 警告:道具 `className` 不匹配。 服务器:“x” 客户端:“y” - Next.Js React app with styled components. Warning: Prop `className` did not match. Server: "x" Client: "y" material-ui客户端警告:道具&#39;style&#39;不匹配 - material-ui client side warning: Prop `style` did not match Remix Hydration 失败:服务器和客户端上的 UI 不匹配 - Remix Hydration failed: UI on server and client do not match `className` 不匹配。 服务器: - `className` did not match. Server: 道具不匹配服务器/客户端,如何生成唯一的持久ID? - Prop mismatch server/client, how to generate a unique ID that persists? 警告 Prop `href` 不匹配。 使用反应服务器端渲染 - Warning Prop `href` did not match. using react server-side-rendering NextJS React 应用程序样式组件未正确呈现:警告:Prop `className` 不匹配 - NextJS React app styled component not rendering correct: Warning: Prop `className` did not match 警告:支持`className`不匹配〜材料UI css在重新加载时任意中断 - Warning: Prop `className` did not match ~ Material UI css arbitrarily breaks on reload 使用 UIkit 和 NextJs 时如何修复“警告:道具类名不匹配” - How to fix “Warning: Prop className did not match” when using UIkit and NextJs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM