簡體   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