我有一个在客户端和服务器上呈现的React应用程序。当任何组件的render()失败时(由于我的代码中的错误,例如尝试读取未定义对象的属性),那么如果我从浏览器中的另一个页面导航,那么我将获得完整的堆栈跟踪浏览器开发者控制台。
但是,当我触发相同代码的服务器端呈现时(通过直接将浏览器指向包含故障组件的有问题的路由),那么我只是在服务器的控制台中得到这样的错误:
nestedlist = []
for counter in range(0,len(firstlist)): #changed line
temporarylist = []
temporarylist.append(firstlist[counter])
temporarylist.append(secondlist[counter])
temporarylist.append(thirdlist[counter])
temporarylist.append(fourthlist[counter])
nestedlist.append(temporarylist)
没有堆栈跟踪,调试有点困难。
问题:有没有办法在服务器端渲染期间覆盖全部渲染()失败?
下面是触发服务器端呈现以响应所请求的Node-Express端点的代码。我相信未处理的promise拒绝发生在renderToString()中,但是这个函数返回一个字符串,而不是一个promise。
`
(node:97192) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property 'tagDefinitionId' of undefined
`
我认为这里可能相关的唯一自定义代码导入是template.js:
`
import configureStore from '../../redux/store';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import React from 'react';
import RouterContext from 'react-router/lib/RouterContext';
import createMemoryHistory from 'react-router/lib/createMemoryHistory';
import match from 'react-router/lib/match';
import template from './template';
import routes from '../../routes';
const clientAssets = require(KYT.ASSETS_MANIFEST);
app.use((request, response) => {
const history = createMemoryHistory(request.originalUrl);
match({ routes, history }, (error, redirectLocation, renderProps) => {
if (error) {
response.status(500).send(error.message);
} else if (redirectLocation) {
response.redirect(302, `${redirectLocation.pathname}${redirectLocation.search}`);
} else if (renderProps) {
// This is the initial store
const store = configureStore();
// When a React Router route is matched then we render
// the components and assets into the template.
const render = () => {
// Grab the initial state from our Redux store
const initialState = JSON.stringify(store.getState());
let isNotFoundRoute = false;
if (renderProps.routes[1].path === '*') {
isNotFoundRoute = true;
}
// Populate the HTML document with the current redux store
response.status(isNotFoundRoute ? 404 : 200).send(template({
root: renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
),
cssBundle: clientAssets.main.css,
jsBundle: clientAssets.main.js,
initialState,
}));
};
// Fetch the components from the renderProps and when they have
// promises, add them to a list of promises to resolve before starting
// a HTML response
fetchComponentData(store.dispatch, renderProps.components, renderProps.params).then(render);
} else {
response.status(404).send('Not found');
}
});
});
`
答案 0 :(得分:1)
是的,您可以使用a catch-all来记录未处理拒绝的堆栈跟踪,但您最好简单地处理它们。实际上,当render
函数中的某些内容抛出异常时,没有任何东西可以捕获它。
我建议将脚本重组为
app.use((request, response) => {
const history = createMemoryHistory(request.originalUrl);
new Promise((resolve, reject) => {
match({ routes, history }, (error, redirectLocation, renderProps) => {
if (error) reject(error);
else resolve({redirectLocation, renderProps});
}).then(({redirectLocation, renderProps}) => {
if (redirectLocation) {
return {status: 302, target: redirectLocation.pathname + redirectLocation.search};
} else if (!renderProps) {
return {status: 404, content: 'Not found'};
} else {
const store = configureStore();
return fetchComponentData(store.dispatch, renderProps.components, renderProps.params).then(() => {
const initialState = JSON.stringify(store.getState());
const isNotFoundRoute = (renderProps.routes[1].path === '*');
const content = template({
root: renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
),
cssBundle: clientAssets.main.css,
jsBundle: clientAssets.main.js,
initialState,
});
return {status: isNotFoundRoute ? 404 : 200, content};
});
}
}).catch(err => { // THIS IS IMPORTANT!
console.error(err); // or err.message and err.stack and everything, maybe including route
return {status: 500, content: 'Sorry, we\'ll look into it'}; // or err.message if you trust it
}).then(({status, target, content}) => {
if (status >= 300 && status < 400)
response.redirect(status, target);
else
respose.status(status).send(content);
if (status >= 400)
console.debug(…)
});
});
答案 1 :(得分:0)
不幸的是,这听起来像是在React @ 15中难以处理的问题。我能想到的唯一方法是为所有组件中的所有渲染方法添加错误处理,这是不可行的。
错误和React的问题直到现在是任何错误都会将React发送到不稳定状态。幸运的是,react@next
(16)带有componentDidCatch
- 一种新的生命周期方法,可以捕获和处理组件或任何后代(子)中的任何错误。
您可以阅读有关此新行为的更多信息in the React team's blog post。
希望这有帮助!