警告:React 尝试在容器中重用标记,但校验和无效 [英] Warning: React attempted to reuse markup in a container but the checksum was invalid

查看:41
本文介绍了警告:React 尝试在容器中重用标记,但校验和无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让同构的 Node.js、Express、Webpack、React 应用程序正常工作.我收到以下错误.关于如何修复它的任何建议?

警告:React 尝试在容器中重用标记,但校验和无效.这通常意味着您正在使用服务器渲染并且服务器上生成的标记不是客户端所期望的.React 注入了新的标记来补偿哪些有效,但您已经失去了服务器渲染的许多好处.相反,找出为什么在客户端或服务器上生成的标记不同:(客户端) rgin:0;display:flex;-webkit-align-items:(服务器) rgin:0;display:flex;align-items:center;j警告@warning.js:45ReactMount._mountImageIntoNode @ ReactMount.js:807包装器 @ ReactPerf.js:66mountComponentIntoNode @ ReactMount.js:268Mixin.perform @ Transaction.js:136batchedMountComponentIntoNode @ ReactMount.js:282Mixin.perform @ Transaction.js:136ReactDefaultBatchingStrategy.batchedUpdates @ ReactDefaultBatchingStrategy.js:62批量更新@ ReactUpdates.js:94ReactMount._renderNewRootComponent @ ReactMount.js:476包装器 @ ReactPerf.js:66ReactMount._renderSubtreeIntoContainer @ ReactMount.js:550ReactMount.render @ ReactMount.js:570包装器 @ ReactPerf.js:66(匿名函数)@client.jsx:14(匿名函数)@iso.js:120每个@iso.js:21引导程序@iso.js:111(匿名函数)@client.jsx:12__webpack_require__@bootstrap d56606d95d659f2e05dc:19(匿名函数)@bootstrap d56606d95d659f2e05dc:39(匿名函数)@bootstrap d56606d95d659f2e05dc:39

这是服务器最初向浏览器传递的内容:

<html lang=""><头><title>我的头衔</title><meta name="apple-mobile-web-app-title" content="我的标题" data-react-helmet="true"/><meta name="apple-mobile-web-app-status-bar-style" content="black" data-react-helmet="true"/><meta name="apple-mobile-web-app-capable" content="yes" data-react-helmet="true"/><meta name="mobile-web-app-capable" content="yes" data-react-helmet="true"/><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" data-react-helmet="true"/><meta name="description" content="我的描述."data-react-helmet="true"/><meta http-equiv="X-UA-Compatible" content="IE=edge" data-react-helmet="true"/><meta charset="utf-8" data-react-helmet="true"/><link rel="stylesheet" href="/assets/styles/reset.css" data-react-helmet="true"/><link rel="stylesheet" href="/assets/styles/base.css" data-react-helmet="true"/><link rel="stylesheet" href="/assets/styles/Carousel.css" data-react-helmet="true"/><link rel="stylesheet" href="/assets/styles/main.css" data-react-helmet="true"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Condensed" type="text/css" data-react-helmet="true"/><link rel="icon" href="/assets/185bb6f691241307862b331970a6bff1.ico" type="image/x-icon" data-react-helmet="true"/>脚本<身体><script src="https://cdn.firebase.com/js/client/2.2.7/firebase.js"></script><script src="https://cdn.firebase.com/libs/reactfire/0.4.0/reactfire.min.js"></script><div class="app"><div class="___iso-html___" data-key="_0"><div data-reactid=".1hkqsbm9n9c" data-react-checksum="794698749"><div data-reactid=".1hkqsbm9n9c.0"><div data-reactid=".1hkqsbm9n9c.0.$=10"></div><div style="position:fixed;z-index:2;top:0;left:0;right:0;height:60px;color:rgb(219,219,219);font-family:mainnextcondensed_ultralight;font-size:17px;overflow:hidden;"data-reactid=".1hkqsbm9n9c.0.$/=11"><div style="position:absolute;left:0;top:0;background-color:rgba(27,27,27,0.92);padding-right:35px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10"><div style="float:left;height:60px;width:13px;border-left:5pxsolid rgb(210,45,164);"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=10"></div><div style="float:left;height:60px;width:227px;背景图像:URL(数据:图像/PNG; BASE64,iVBORw0KGgoAAAANSUhEUgAAAOMAAAAhCAYAAAArrhzzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACxNJREFUeNrsXF9sHEcZHx927MZJvU5cSw4FrxXahja451Q88ADeq5Aq0aKeKyh9oMqdyFNA9PzAY3U2vPDE3SGBxNOdaZHKC3c8FCgqvXP73PjqFiSSIl9oSSTXJOe4juv8M/OTV/F9O57ZP + dzaWF + ysjZ3dmd2dn5ze/7vpm5LtYGFr/0otV7wsrdXr1x8dbl6zV + qj7 + 9nebUZ6xtbXFDAwMWoiFJZ90qjjw7eOp0fJj2XtfeLR6d9Je4nls05wGBu2jO4CENlfABZ7YInsxwU + B + mV77x9Ixg73uHl67xtgR39w0rpWaQAZG6ZJDQw6TEZQw77xo + WRn33Fih3qYQfG7l6Av/2TIwz + euSVHx/+ 5miOE3aam6s106wGBtHR5UPG4vDzj6QOP/750A9be/mf7Mqv/PA/tbwxG + RDGp/RwCAEGTkRU + AXgin6uV8/yrpHDoZ + 4J0Pb7LlH79Z/+ idK43Dj486zRfOpzkxK4aMBgYRyciJGOd/qjy5QZtjv/wqu + vUUNsF/PsXf21yQiY4IeuGjAYGIX1GjJoWBRFBEVVE3Di3wtZfv8RunF9loJ79Xzum9CUBR7//kHV7eaPM/cmJqNMfXV1dofJhveN46JlmwcHFfR/jzxp8asjIkSOdWklE8AuXf/Km59z6/GUWy/ewI2e + YAA + c3zXPUM/ethee + U9MH3z +/QeZZ4c/D9EfWtIRAdVPtBHNjD4xJAR/cQUvdgz0u/JfOvy9V1E3PEV126yldwi2zzfZMPPP + K59uGr/wKlquzHC/B6zxAiympZNp + 4S + Duhc3/2MIK4dZL09Sxg2REUy5HFXGQq1zQXUr8r8NuXx8bwdIpVC10ySPX/szJBm0w4yijsJqAYXOk/rBNyuBegtV7DB2BtEQ3yawvWMYZYSHzomToGowX + iLA1us7 + RwK0iTPsX6vzHs8S/XX7 + 8c3zo6/daHVSrJHZegYoUhLIU59vFpGh4JA6YKrOYmholzRIigulaArOUJ + goY1ivmuiM2Elr + GEthbln0 + 8TBUiOKWyTXJuDHsOBSIc0aXsZBTKg0PcS/aESQMbnUCzgOZaswPicDJq5eU0b7AcRGekDRfm7tYOYymcEvPfsa2wlv8i8pus9JGLD/63f8EZNv3eKsYO3SZT1Uss5HTkI0dYsLyujWHge1TylpgGQ4y3JhGBEyfYKYbLFedmuucpJNYOpoTEpBaZkSwCOeYLzQFKqNHNY96SiMwrrhe2BkHUV2UMEQuKoik2f5wtfO​​I73yH5rXfFewnyf8ylfWCVzqDwNRYwgSdrv40YDCWn5mKvhySjPLVJlA99v80LLTzw4OUIcyBhb + 8uSNxp0T7 + rmDtZLnh9zMEzJ + yxV5/IwfarPdS5TOoq1EaFqQ6ZxCWigK7Jx9tsCdVZhVHRCTVk1XVoUc5pRWer + AUuQuL3xP/X +FqKlCImP5MGOx3eku6R1dGWfOIwpncW89QI4Ww0vZlUXlT1O616d78gi + a75YlV44QY4LTtHUObPK67efWlVgQVdmjQucf1Py2z1T/8fed4s3GVM7A1lbcpB3zQf + x76IjdpipmiF/rp3z5Tk3wI6HAtMwTUtpIyrjPrc02ie8IdcHOa + 3zqK8KJjQ6XEaFDjMK2Nq6LMVic8tpkLcb9uJ6YcAdaxjf7H9fGFde9PfwNEu4l57 + ALY/OCZE + 7EPpitYukcTmG4W69k3Fi6FinCqJjGqKj2RpJRKSwSUpTUj7x5tntOEd4h4fcu/Foa69RQ + GFTeF1nGlakCGhY5MigUkZVL6DC6NqtqklxKdIrlofBih4XRHETKkXyGWj8TO9MiKCVeE6W1DFBVHwJ63cV + w8QdeJjWqOaD4jDaNu7S + r8RaZZcgQEA/LtBRenXpl98M9PzeAIEZj/7fHfWJL5HPlX6FBZBUFqGsKrTPSmvAcTg0gNaYuWdvuWXI//hS1cqC477/sJXSgeJ/GFT81C8S5FZ1vQZR6aHnd3ZcBCcCCnav + iLxmf + GPpweq30mHJaGDw/wSZjBkWcskUmKVHM + ORfgUAltldOvsGbDKuGzIaGEgBHIU/Ewowoc + JtWvJHAXMT9LdG/KKHAMDA40yRlVHAfo7OUDA7S1UH + wQ0Q3w3GfBTo40RjONmWpgEERGJOQMcIi19t/5AsgmNhOjKborGMK2N + OWiJNtWt/AIIiMEjGTzDtRrQWoI0xtSIsBgIjm1 + EMDPZKxr2Yr6y1n0/1swSm9Q0MCGJhM + Lkt26 + BsxPmLKASCn9uYNEB3f2GxgYZZRMVlj1ICZ9a2x7eVojasFGGQ0M9kBGQkrwHy3ZDzRkNDBoH/8RYAC6QbxY8FBYtQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:center;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=11"></div><div style="display:none;width:0;height:0;边框样式:实心;边框宽度:6px 6px 0 6px;边框颜色:rgb(117,117,117)透明透明透明;-webkit-transform:旋转(360度);浮动:左;左边距:6像素;边距顶部:26px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=12"></div></div><div style="position:absolute;top:0px;左:280像素;宽度:340像素;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11"><div style="background-color:rgba(27,27,27,0.92);height:10px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=10"></div><div style="background-color:rgba(53,53,53,0.84);高度:40px;位置:相对;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:-58px -194px;width:23px;height:22px;position:absolute;top:50%;margin:顶部:-11px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10.$icon"></div></div><div style="位置:绝对;左:40 像素;右:40 像素;顶部:0 像素;底部:0 像素;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12"><input type="text" style="width:100%;height:100%;字体大小:14px;字体系列:mainnext_regular;背景颜色:透明;颜色:#ffffff;"placeholder="搜索艺术家、曲目、专辑" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12.0"/></div></div><div style="background-color:rgba(27,27,27,0.92);height:10px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=12"></div></div><div style="position:absolute;top:0px;left:620px;right:0px;background-color:rgba(27,27,27,0.92);height:60px;line-height:60px;overflow:hidden;min-width:500px;padding-left:10px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12"><div style="position:absolute;top:0px;bottom:0px;right:0px;width:357px;padding-左:141 像素;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0"><a class="" href="/import" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10"><div style="padding-left:40px;position:absolute;left:0px;top:10px;bottom:10px;cursor:pointer;line-height:40px;颜色:RGB(255,255,255);"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:0px -194px;width:28px;height:28px;position:absolute;top:0px;%;边距顶部:-14px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10.$icon"></div></div><spandata-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.1">导入播放列表</span></div></a><div style="margin-left:10px;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin"><div style="cursor:pointer;float:left;"data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin.$login">登录</div></div></div></div></div></div><noscript data-reactid=".1hkqsbm9n9c.1"></noscript></div></div><div class="___iso-state___" data-key="_0" data-meta="{}" data-state=""{&quot;UserStore&quot;:{&;quot;用户":{"经过身份验证的":false,"isWaiting":false}},"SearchStore&quot;:{"focused&quot;:false,"input&quot;:&quot;&quot;,"timeout&quot;:null,"searchRequests":[],"artists":null,"artistsFailed":false,;"artistsLoading":false,"tracks":null,"tracksFailed":false,"tracksLoading";:false,"albums":null,"albumsFailed":false,"albumsLoading":false,";播放列表":null,"播放列表失败":false,"播放列表加载":false,"youtubes":null,"youtubesFailed":false,"youtubeesLoading":false,"soundclouds":null,"soundcloudsFailed":false,"soundcloudsLoading":false},"PlayerStore":{"player":null,"playerSecond":null,"playingTrack&quot;:null,"playingTrackSecond&quot;:null,"videoId&quot;:null,"videoIdSecond":null,&quot;makingPlayingTrackPlayable&quot;:false,"radio":false,"startSeconds":0,"current&quot;:0,"total":0,"perc":0,"currentSecond&quot;:0,&quot;totalSecond&quot;:0,"percSecond":0,"playing&quot;:false,"playingSecond&quot;:false,"secondsListened":0,"secondsListenedSecond":0,"expand":false,";源":null,";tracksQueue":[],"tracksPrevQueue":[],"favorite&quot;:false,"random&quot;;:false,"repeat":false,"mute":false,"volume":100,";模式":&quot;标准"},"ImportStore&quot;:{"url&quot;:&quot;","error":false,"focused":false,"loading":false,"已加载":false,"播放列表":null}}""></div>

<!-- Google Analytics:将 UA-XXXXX-X 更改为您网站的 ID --><!--<脚本>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('创建', 'UA-XXXXX-X', '自动');ga('发送', '浏览量');--><script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.3/fastclick.min.js"></script><script type="text/javascript">if ('addEventListener' in document) {document.addEventListener('DOMContentLoaded', function() {FastClick.attach(document.body);}, 错误的);}<script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>

这是我的 server.jsx:

从'iso'导入iso;从反应"导入反应;从react-dom/server"导入 ReactDomServer;从反应路由器"导入 { RoutingContext, match }从'history/lib/createLocation'导入createLocation;从'altInstance'导入alt;从'routes.jsx'导入路由;从'base.html'导入html;/** @param {AltObject} Alt 对象的实例* @param {ReactObject} 路由在 react-router 中指定* @param {Object} 用于引导我们的 altStores 的数据* @param {Object} req 从 Express/Koa 服务器传递*/const renderToMarkup = (alt, state, req, res) =>{让标记,内容;让 location = new createLocation(req.url);alt.bootstrap(状态);匹配({路线,位置},(错误,redirectLocation,renderProps)=> {如果(重定向位置)res.redirect(301,redirectLocation.pathname + redirectLocation.search)否则如果(错误)res.status(500).send(error.message)否则如果(renderProps == null)res.status(404).send('未找到')别的content = ReactDomServer.renderToString(<RoutingContext {...renderProps}/>);标记 = Iso.render(content, alt.flush());});返回标记;};/** 导出渲染函数用于 server/config/routes.js* 我们获取从服务器传入的状态和从 Express/Koa 获取的 req 对象* 并将其传递给 Router.run 函数.*/导出默认函数渲染(状态,请求,资源){const markup = renderToMarkup(alt, state, req, res);返回 html.replace('内容', 标记);};

这是我的 client.jsx:

从'react'导入React;从 'react-dom' 导入 ReactDOM;从iso"导入iso;从'history/lib/createBrowserHistory'导入createBrowserHistory;从反应路由器"导入{路由器};从'altInstance'导入alt;从'routes.jsx'导入路由;/**带有iso和alt的客户端引导程序*/Iso.bootstrap((状态,_,容器)=> {alt.bootstrap(状态);ReactDOM.render(<Router history={createBrowserHistory()} children={routes}/>, container);});

还有我的 routes.jsx:

从'react'导入React;从反应路由器"导入路由;从组件/应用程序"导入应用程序;从组件/导入播放列表"导入导入播放列表;从组件/登录"导入登录;从组件/注销"导入注销;从组件/播放器/播放器"导入播放器;从组件/测试"导入测试;导出默认值 (<Route path="/" component={App}><Route path="login" component={Login}/><Route path="logout" component={Logout}/><Route name="test" path="test" component={Test}/><Route name="import" path="import" component={ImportPlaylist}/><Route name="player" path="/:playlist" component={Player}/></路线>);

解决方案

注意: 这适用于旧版本的 React.如果你使用的是 React 16,你应该使用 ReactDOM.hydrate()

此外,以下建议将导致客户端重新呈现,如以下答案之一所建议的那样.

<小时>

这听起来可能非常简单,但在您的服务器端模板中,将您的 React 标记包装在额外的 <div> 中:

<section role="main" class="react-container"><div>{{{reactMarkup}}}</div></section>

为什么会这样?在客户端,React 倾向于使用多余的 div 来包装其对根组件的渲染.ReactDOMServer.render 似乎不会以这种方式运行,因此当同构渲染到同一个容器中时,DOM 的 Adler-32 校验和会有所不同.

I'm trying to get an isomorphic Node.js, Express, Webpack, React app working. I'm getting the following error. Any suggestions on how to fix it?

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
 (client) rgin:0;display:flex;-webkit-align-items:
 (server) rgin:0;display:flex;align-items:center;j

warning @   warning.js:45
ReactMount._mountImageIntoNode  @   ReactMount.js:807
wrapper @   ReactPerf.js:66
mountComponentIntoNode  @   ReactMount.js:268
Mixin.perform   @   Transaction.js:136
batchedMountComponentIntoNode   @   ReactMount.js:282
Mixin.perform   @   Transaction.js:136
ReactDefaultBatchingStrategy.batchedUpdates @   ReactDefaultBatchingStrategy.js:62
batchedUpdates  @   ReactUpdates.js:94
ReactMount._renderNewRootComponent  @   ReactMount.js:476
wrapper @   ReactPerf.js:66
ReactMount._renderSubtreeIntoContainer  @   ReactMount.js:550
ReactMount.render   @   ReactMount.js:570
wrapper @   ReactPerf.js:66
(anonymous function)    @   client.jsx:14
(anonymous function)    @   iso.js:120
each    @   iso.js:21
bootstrap   @   iso.js:111
(anonymous function)    @   client.jsx:12
__webpack_require__ @   bootstrap d56606d95d659f2e05dc:19
(anonymous function)    @   bootstrap d56606d95d659f2e05dc:39
(anonymous function)    @   bootstrap d56606d95d659f2e05dc:39

This is what is being delivered by the server to the browser initially:

<!doctype html>
<html lang="">

    <head>
        <title>my title</title>

        <meta name="apple-mobile-web-app-title" content="my title" data-react-helmet="true" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" data-react-helmet="true" />
<meta name="apple-mobile-web-app-capable" content="yes" data-react-helmet="true" />
<meta name="mobile-web-app-capable" content="yes" data-react-helmet="true" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" data-react-helmet="true" />
<meta name="description" content="my description." data-react-helmet="true" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" data-react-helmet="true" />
<meta charset="utf-8" data-react-helmet="true" />

        <link rel="stylesheet" href="/assets/styles/reset.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/base.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/Carousel.css" data-react-helmet="true" />
<link rel="stylesheet" href="/assets/styles/main.css" data-react-helmet="true" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Condensed" type="text/css" data-react-helmet="true" />
<link rel="icon" href="/assets/185bb6f691241307862b331970a6bff1.ico" type="image/x-icon" data-react-helmet="true" />

        SCRIPT

    </head>
    <body>
        <script src="https://cdn.firebase.com/js/client/2.2.7/firebase.js"></script>
        <script src="https://cdn.firebase.com/libs/reactfire/0.4.0/reactfire.min.js"></script>

        <div class="app">
<div class="___iso-html___" data-key="_0"><div data-reactid=".1hkqsbm9n9c" data-react-checksum="794698749"><div data-reactid=".1hkqsbm9n9c.0"><div data-reactid=".1hkqsbm9n9c.0.$=10"></div><div style="position:fixed;z-index:2;top:0;left:0;right:0;height:60px;color:rgb(219,219,219);font-family:mainnextcondensed_ultralight;font-size:17px;overflow:hidden;" data-reactid=".1hkqsbm9n9c.0.$/=11"><div style="position:absolute;left:0;top:0;background-color:rgba(27,27,27,0.92);padding-right:35px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10"><div style="float:left;height:60px;width:13px;border-left:5px solid rgb(210,45,164);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=10"></div><div style="float:left;height:60px;width:227px;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=11"></div><div style="display:none;width:0;height:0;border-style:solid;border-width:6px 6px 0 6px;border-color:rgb(117,117,117) transparent transparent transparent;-webkit-transform:rotate(360deg);float:left;margin-left:6px;margin-top:26px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=12"></div></div><div style="position:absolute;top:0px;left:280px;width:340px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11"><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=10"></div><div style="background-color:rgba(53,53,53,0.84);height:40px;position:relative;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:-58px -194px;width:23px;height:22px;position:absolute;top:50%;left:10px;margin-top:-11px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10.$icon"></div></div><div style="position:absolute;left:40px;right:40px;top:0px;bottom:0px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12"><input type="text" style="width:100%;height:100%;font-size:14px;font-family:mainnext_regular;background-color:transparent;color:#ffffff;" placeholder="SEARCH ARTISTS, TRACKS, ALBUMS" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12.0"/></div></div><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=12"></div></div><div style="position:absolute;top:0px;left:620px;right:0px;background-color:rgba(27,27,27,0.92);height:60px;line-height:60px;overflow:hidden;min-width:500px;padding-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12"><div style="position:absolute;top:0px;bottom:0px;right:0px;width:357px;padding-left:141px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0"><a class="" href="/import" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10"><div style="padding-left:40px;position:absolute;left:0px;top:10px;bottom:10px;cursor:pointer;line-height:40px;color:rgb(255,255,255);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:0px -194px;width:28px;height:28px;position:absolute;top:50%;left:0px;margin-top:-14px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10.$icon"></div></div><span data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.1">Import Playlists</span></div></a><div style="margin-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin"><div style="cursor:pointer;float:left;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin.$login">Login</div></div></div></div></div></div><noscript data-reactid=".1hkqsbm9n9c.1"></noscript></div></div>
<div class="___iso-state___" data-key="_0" data-meta="{}" data-state="&quot;{&quot;UserStore&quot;:{&quot;user&quot;:{&quot;authenticated&quot;:false,&quot;isWaiting&quot;:false}},&quot;SearchStore&quot;:{&quot;focused&quot;:false,&quot;input&quot;:&quot;&quot;,&quot;timeout&quot;:null,&quot;searchRequests&quot;:[],&quot;artists&quot;:null,&quot;artistsFailed&quot;:false,&quot;artistsLoading&quot;:false,&quot;tracks&quot;:null,&quot;tracksFailed&quot;:false,&quot;tracksLoading&quot;:false,&quot;albums&quot;:null,&quot;albumsFailed&quot;:false,&quot;albumsLoading&quot;:false,&quot;playlists&quot;:null,&quot;playlistsFailed&quot;:false,&quot;playlistsLoading&quot;:false,&quot;youtubes&quot;:null,&quot;youtubesFailed&quot;:false,&quot;youtubesLoading&quot;:false,&quot;soundclouds&quot;:null,&quot;soundcloudsFailed&quot;:false,&quot;soundcloudsLoading&quot;:false},&quot;PlayerStore&quot;:{&quot;player&quot;:null,&quot;playerSecond&quot;:null,&quot;playingTrack&quot;:null,&quot;playingTrackSecond&quot;:null,&quot;videoId&quot;:null,&quot;videoIdSecond&quot;:null,&quot;makingPlayingTrackPlayable&quot;:false,&quot;radio&quot;:false,&quot;startSeconds&quot;:0,&quot;current&quot;:0,&quot;total&quot;:0,&quot;perc&quot;:0,&quot;currentSecond&quot;:0,&quot;totalSecond&quot;:0,&quot;percSecond&quot;:0,&quot;playing&quot;:false,&quot;playingSecond&quot;:false,&quot;secondsListened&quot;:0,&quot;secondsListenedSecond&quot;:0,&quot;expand&quot;:false,&quot;source&quot;:null,&quot;tracksQueue&quot;:[],&quot;tracksPrevQueue&quot;:[],&quot;favorite&quot;:false,&quot;random&quot;:false,&quot;repeat&quot;:false,&quot;mute&quot;:false,&quot;volume&quot;:100,&quot;mode&quot;:&quot;standard&quot;},&quot;ImportStore&quot;:{&quot;url&quot;:&quot;&quot;,&quot;error&quot;:false,&quot;focused&quot;:false,&quot;loading&quot;:false,&quot;loaded&quot;:false,&quot;playlist&quot;:null}}&quot;"></div>
</div>

        <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
        <!--
        <script>
            (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
                (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
                    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
            })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
            ga('create', 'UA-XXXXX-X', 'auto');
            ga('send', 'pageview');
        </script>
        -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.3/fastclick.min.js"></script>
        <script type="text/javascript">
          if ('addEventListener' in document) {
            document.addEventListener('DOMContentLoaded', function() {
                FastClick.attach(document.body);
            }, false);
          }
        </script>
        <script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>
    </body>
</html>

This is my server.jsx:

import Iso from 'iso';
import React from 'react';
import ReactDomServer from 'react-dom/server';
import { RoutingContext, match } from 'react-router'
import createLocation from 'history/lib/createLocation';

import alt from 'altInstance';
import routes from 'routes.jsx';
import html from 'base.html';

/*
 * @param {AltObject} an instance of the Alt object
 * @param {ReactObject} routes specified in react-router
 * @param {Object} Data to bootstrap our altStores with
 * @param {Object} req passed from Express/Koa server
 */
const renderToMarkup = (alt, state, req, res) => {
  let markup, content;
  let location = new createLocation(req.url);
  alt.bootstrap(state);

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    if (redirectLocation)
      res.redirect(301, redirectLocation.pathname + redirectLocation.search)
    else if (error)
      res.status(500).send(error.message)
    else if (renderProps == null)
      res.status(404).send('Not found')
    else
      content = ReactDomServer.renderToString(<RoutingContext {...renderProps} />);
      markup = Iso.render(content, alt.flush());
  });

  return markup;
};

/* 
 * Export render function to be used in server/config/routes.js
 * We grab the state passed in from the server and the req object from Express/Koa
 * and pass it into the Router.run function.
 */
export default function render(state, req, res) {
  const markup = renderToMarkup(alt, state, req, res);
  return html.replace('CONTENT', markup);
};

And this is my client.jsx:

import React from 'react';
import ReactDOM from 'react-dom';
import Iso from 'iso';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import { Router } from 'react-router';
import alt from 'altInstance';
import routes from 'routes.jsx';

/*
 * Client side bootstrap with iso and alt
 */
Iso.bootstrap((state, _, container) => {
  alt.bootstrap(state);
  ReactDOM.render(<Router history={createBrowserHistory()} children={routes} />, container);
});

And my routes.jsx:

import React from 'react';
import Route from 'react-router';
import App from 'components/App';
import ImportPlaylist from 'components/ImportPlaylist';
import Login from 'components/Login';
import Logout from 'components/Logout';
import Player from 'components/Player/Player';
import Test from 'components/Test';

export default (
  <Route path="/" component={App}>
    <Route path="login" component={Login} />
    <Route path="logout" component={Logout} />
    <Route name="test" path="test" component={Test} />        
    <Route name="import" path="import" component={ImportPlaylist} />
    <Route name="player" path="/:playlist" component={Player} />
  </Route>
);

解决方案

Note: This applies to older versions of React. If you're using React 16, you should use ReactDOM.hydrate()

Also, the below suggestion will result in a client-side re-render, as suggested by one of the answers below.


This may sound crazily simple, but in your server-side template, wrap your React markup in an extra <div>:

<!-- hypothetical handlebars template -->
<section role="main" class="react-container"><div>{{{reactMarkup}}}</div></section>

Why does this work? On the client, React has a propensity to wrap its rendering of your root component with a superfluous div. ReactDOMServer.render doesn't seem to behave in this manner, thus when one renders into the same container isomorphically, the Adler-32 checksum of your DOM differs.

这篇关于警告:React 尝试在容器中重用标记,但校验和无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆