gpt4 book ai didi

javascript - react 校验和无效的服务器渲染

转载 作者:行者123 更新时间:2023-11-27 23:20:58 24 4
gpt4 key购买 nike

在我的 React 应用程序中,我当前正在使用服务器端渲染。我当前收到的错误是:

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) <noscript data-reacti
(server) <div data-reactid=".1

服务器.js:

 import 'babel-polyfill';
import path from 'path';
import express from 'express';
import React from 'react';
import ReactDOM from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import assets from './assets';
import { port } from './config';
import routes from './routes';
import ContextHolder from './core/ContextHolder';
import Html from './components/Html';

const server = global.server = express();

//
// Register Node.js middleware
// -----------------------------------------------------------------------------
server.use(express.static(path.join(__dirname, 'public')));

//
// Register API middleware
// -----------------------------------------------------------------------------
server.use('/api/content', require('./api/content').default);

//
// Register server-side rendering middleware
// -----------------------------------------------------------------------------
server.get('*', async (req, res, next) => {
try {
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
throw error;
}
if (redirectLocation) {
const redirectPath = `${ redirectLocation.pathname }${ redirectLocation.search }`;
res.redirect(302, redirectPath);
return;
}
let statusCode = 200;
const data = { title: '', description: '', css: '', body: '', entry: assets.main.js };
const css = [];
const context = {
insertCss: styles => css.push(styles._getCss()),
onSetTitle: value => data.title = value,
onSetMeta: (key, value) => data[key] = value,
onPageNotFound: () => statusCode = 404,
};
data.body = ReactDOM.renderToString(
<ContextHolder context={context}>
<RouterContext {...renderProps}/>
</ContextHolder>
);
data.css = css.join('');
const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);
res.status(statusCode).send(`<!doctype html>\n${html}`);
});
} catch (err) {
next(err);
}
});

//
// Launch the server
// -----------------------------------------------------------------------------
server.listen(port, () => {
/* eslint-disable no-console */
console.log(`The server is running at http://localhost:${port}/`);
});

客户端.js:

import 'babel-polyfill';
import React from 'react';
import { match, Router } from 'react-router';
import { render } from 'react-dom';
import FastClick from 'fastclick';
import routes from './routes';
import Location from './core/Location';
import ContextHolder from './core/ContextHolder';
import { addEventListener, removeEventListener } from './core/DOMUtils';

let cssContainer = document.getElementById('css');
const appContainer = document.getElementById('app');
const context = {
insertCss: styles => styles._insertCss(),
onSetTitle: value => document.title = value,
onSetMeta: (name, content) => {
// Remove and create a new <meta /> tag in order to make it work
// with bookmarks in Safari
const elements = document.getElementsByTagName('meta');
[].slice.call(elements).forEach((element) => {
if (element.getAttribute('name') === name) {
element.parentNode.removeChild(element);
}
});
const meta = document.createElement('meta');
meta.setAttribute('name', name);
meta.setAttribute('content', content);
document.getElementsByTagName('head')[0].appendChild(meta);
},
};

function run() {
const scrollOffsets = new Map();
let currentScrollOffset = null;

// Make taps on links and buttons work fast on mobiles
FastClick.attach(document.body);

const unlisten = Location.listen(location => {
const locationId = location.pathname + location.search;
if (!scrollOffsets.get(locationId)) {
scrollOffsets.set(locationId, Object.create(null));
}
currentScrollOffset = scrollOffsets.get(locationId);
// Restore the scroll position if it was saved
if (currentScrollOffset.scrollY !== undefined) {
window.scrollTo(currentScrollOffset.scrollX, currentScrollOffset.scrollY);
} else {
window.scrollTo(0, 0);
}
});

const { pathname, search, hash } = window.location;
const location = `${pathname}${search}${hash}`;

match({ routes, location }, (error, redirectLocation, renderProps) => {
render(
<ContextHolder context={context}>
<Router {...renderProps} children={routes} history={Location} />
</ContextHolder>,
appContainer
);
// Remove the pre-rendered CSS because it's no longer used
// after the React app is launched
if (cssContainer) {
cssContainer.parentNode.removeChild(cssContainer);
cssContainer = null;
}
});

// Save the page scroll position
const supportPageOffset = window.pageXOffset !== undefined;
const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');
const setPageOffset = () => {
if (supportPageOffset) {
currentScrollOffset.scrollX = window.pageXOffset;
currentScrollOffset.scrollY = window.pageYOffset;
} else {
currentScrollOffset.scrollX = isCSS1Compat ?
document.documentElement.scrollLeft : document.body.scrollLeft;
currentScrollOffset.scrollY = isCSS1Compat ?
document.documentElement.scrollTop : document.body.scrollTop;
}
};

addEventListener(window, 'scroll', setPageOffset);
addEventListener(window, 'pagehide', () => {
removeEventListener(window, 'scroll', setPageOffset);
unlisten();
});
}

// Run the application when both DOM is ready and page content is loaded
if (['complete', 'loaded', 'interactive'].includes(document.readyState) && document.body) {
run();
} else {
document.addEventListener('DOMContentLoaded', run, false);
}

这是我第一次探索服务器端渲染。我知道这意味着服务器和客户端正在渲染两个不同的东西,因此客户端必须重新渲染任何东西。它没有破坏任何东西,但我想知道如何解决这个问题,这样警告就会消失。

最佳答案

此问题与异步路由有关。除了更改所有要同步的路由之外,我没有找到其他解决方案。 <noscript>加载异步路由时,客户端添加的标签会放置在那里。

示例,更改:

const routes = {
path: '/',
getComponent: function(location, cb) {
require.ensure([], function(require) {
return cb(null, require('./views/homepage'));
})
};
};

进入此:

const routes = {
path: '/',
getComponent: function(location, cb) {
return cb(null, require('./views/homepage'));
};
};

编辑:要重新启用异步路由,请在客户端路由器中执行以下操作:

match({ history, routes }, (error, redirectLocation, renderProps) => {
render(<Router {...renderProps} />, mountNode)
})

感谢@firasd在这里回答编辑:Async Routes Causes Server-Side Checksum Invalid Error

关于javascript - react 校验和无效的服务器渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35368285/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com