使用 React 路由器进行服务器端渲染
Server side rendering with React router
我可以在不使用 redux 或任何存储容器的情况下为我的页面进行服务器端呈现,而只是对路由器做出反应。我的初始页面从 api 获取一些数据。我应该如何将其传递给服务器上的反应组件。如果我在服务器上使用 window 变量,我会收到一条错误消息,提示 window 未定义。任何帮助都会很好。
我不想用,redux。我尝试获取初始数据状态,如何将其传递给服务器端的组件。使用 window 变量没有帮助,因为 window 未在服务器上定义。
clientRouter.get('/', (req, res) => {
match({routes : routes, location: req.url}, (err, redirect, props) => {
if (err) {
res.status(500).send(err.message)
} else if (redirect) {
res.redirect(redirect.pathname + redirect.search)
} else if (props) {
let todos = [{id: 1, title: "Hey loo"}, {id: 2, title: "Meoww"}];
props.todos = todos
**** how do i pass the todos state down to the components****
const appHtml = renderToString(<RouterContext {...props}/>);
res.send(renderPage(appHtml, todos))
// if we got props then we matched a route and can render
} else {
// no errors, no redirect, we just didn't match anything
res.status(404).send('Not Found')
}
})
})
以上方法无效
function renderPage(appHtml, state) {
let initialState = JSON.stringify(state);
return `
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Judo Heroes - A Universal JavaScript demo application with React</title>
<link rel="stylesheet" href="./../build/${cssSrc}">
</head>
<body>
<div id="main">${appHtml}</div>
<script>window.INIT_STATE = ${initialState}</script>
<script src=./../build/${jsSrc}></script>
</body>
</html>
`
}
我创建了一个 boilerplate,其中使用 EJS 启用了 SSR。
我使用 EJS(嵌入式 JS)在 html 中注入带有预加载数据的标记。
您可以点击 server.js 中的 api 并将数据作为 preloadedData 加载到您的 html 标记中
// universal routing and rendering
app.get('*', (req, res) => {
// if the current route matched we have renderProps
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
// in case of error display the error message
if (err) {
return res.status(500).send(err.message);
}
// in case of redirect propagate the redirect to the browser
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
// generate the React markup for the current route
let markup = "";
if (renderProps) {
let preloadedData = [];
fetch("http://example.com").then(function (data) {
preloadedData = [data.data];
renderSSRPage(res, preloadedData, renderProps);
}.bind(this)).catch(function (err) {
preloadedData = [{ error: true }];
renderSSRPage(res, preloadedData, renderProps);
console.warn('Error in server.js ', err)
});
res.render('index', {
markup,
preloadedData: JSON.stringify(preloadedData)
});
}
}
)
}
我可以在不使用 redux 或任何存储容器的情况下为我的页面进行服务器端呈现,而只是对路由器做出反应。我的初始页面从 api 获取一些数据。我应该如何将其传递给服务器上的反应组件。如果我在服务器上使用 window 变量,我会收到一条错误消息,提示 window 未定义。任何帮助都会很好。
我不想用,redux。我尝试获取初始数据状态,如何将其传递给服务器端的组件。使用 window 变量没有帮助,因为 window 未在服务器上定义。
clientRouter.get('/', (req, res) => {
match({routes : routes, location: req.url}, (err, redirect, props) => {
if (err) {
res.status(500).send(err.message)
} else if (redirect) {
res.redirect(redirect.pathname + redirect.search)
} else if (props) {
let todos = [{id: 1, title: "Hey loo"}, {id: 2, title: "Meoww"}];
props.todos = todos
**** how do i pass the todos state down to the components****
const appHtml = renderToString(<RouterContext {...props}/>);
res.send(renderPage(appHtml, todos))
// if we got props then we matched a route and can render
} else {
// no errors, no redirect, we just didn't match anything
res.status(404).send('Not Found')
}
})
})
以上方法无效
function renderPage(appHtml, state) {
let initialState = JSON.stringify(state);
return `
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Judo Heroes - A Universal JavaScript demo application with React</title>
<link rel="stylesheet" href="./../build/${cssSrc}">
</head>
<body>
<div id="main">${appHtml}</div>
<script>window.INIT_STATE = ${initialState}</script>
<script src=./../build/${jsSrc}></script>
</body>
</html>
`
}
我创建了一个 boilerplate,其中使用 EJS 启用了 SSR。
我使用 EJS(嵌入式 JS)在 html 中注入带有预加载数据的标记。
您可以点击 server.js 中的 api 并将数据作为 preloadedData 加载到您的 html 标记中
// universal routing and rendering
app.get('*', (req, res) => {
// if the current route matched we have renderProps
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
// in case of error display the error message
if (err) {
return res.status(500).send(err.message);
}
// in case of redirect propagate the redirect to the browser
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
// generate the React markup for the current route
let markup = "";
if (renderProps) {
let preloadedData = [];
fetch("http://example.com").then(function (data) {
preloadedData = [data.data];
renderSSRPage(res, preloadedData, renderProps);
}.bind(this)).catch(function (err) {
preloadedData = [{ error: true }];
renderSSRPage(res, preloadedData, renderProps);
console.warn('Error in server.js ', err)
});
res.render('index', {
markup,
preloadedData: JSON.stringify(preloadedData)
});
}
}
)
}