そのため、SEO に最適化されたコンテンツ (=== サーバー上でレンダリングされる) が必要な POC アプリに取り組んでいます。ただし、同じルート内に、さまざまなソースからの動的データが存在する可能性があり、そのすべてのデータをキャプチャするのに時間がかかる場合があります。この動的データは SEO には必要ないため、非同期ロードが実装されます。
私がこれまでに持っているのは、次のようなものです (これは単なるサンプルであることに注意してください):
// routes.js
import serverRender from './services/aboutService';
const routes = (
<Route path="/" component={Layout}>
<IndexRoute component={Home}/>
<Route path="/about">
<Route
path="/About"
component={AboutContainer}
serverRender={serverRender} />
</Route>
</Route>
);
// aboutService.js
const serverRender = () => {
return axios.get("http://localhost:3002/services/about")
.then(res => res.data)
.catch(function (error) {
console.log(error);
});
}
export default serverRender;
// AboutContainer.js
import React from 'react';
export default class About extends Component {
constructor(props){
super(props);
this.state = {
data: { username: "", isFetching : true, hasError: false }
};
this._fetchNonSEOData = this.fetchNonSEOData.bind(this);
console.log("CompetitionContainer constructor: ", props)
}
componentDidMount(){
//this._fetchNonSEOData();
}
_fetchNonSEOData(){
// dynamic content, not important for Crawlers
// will call setState here to update state properties
}
render(){
return (
<div>
<h1>User: {this.props.data.username}</h1>
<div className="non-seo">
{this._fetchNonSEOData()}
</div>
</div>
)
}
}
ExpressJS を使用している server.js (その小さなスライス):
// server.js app.get('*', (req, res) => { ReactRouter.match({ routes, location: req.url }, (err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
}
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
let markup;
if (renderProps) {
preRenderMiddleware(renderProps)
.then(data => {
const appElement = (
<ReactRouter.RouterContext
{...renderProps}
createElement={(Component, props) => {
return <Component data={data} {...props} />;
}}
/>
);
//
let markup = ReactDOMServer.renderToString(appElement);
console.log("AppString:", markup)
return res.render('index', { markup, head });
})
} else {
// otherwise we can render a 404 page
markup = ReactDOMServer.renderToString(<NotFoundPage/>);
res.status(404);
}
});
});
ご覧のとおり、解決された Promise を返す preRenderMiddleware があり、これは私が間違っていると思われる部分です。
//preRenderMiddleware.js
const defaultServerRender = () => Promise.resolve();
function preRenderMiddleware({ routes, location, params }) {
const matchedRoute = routes[routes.length - 1];
const serverRenderHandler = matchedRoute.serverRender || defaultServerRender;
return serverRenderHandler(params);
}
したがって、私の問題は、サーバーから期待されるマークアップを取得することです-AboutContainer this.props.data でデータを取得しています。しかし、クライアント側が起動すると、 this.props.data は未定義です。
誰かが私に良い解決策を教えてくれますか? 私はこの問題を抱えた最初の人ではないと確信しています。これに対するいくつかの解決策に出くわしましたが、クライアント上で再要求された同じデータはすべて回避したいものであり、同じことは少し奇妙です。
また、Redux / Fluxを使用したくありません。
何かご意見は?