我正在尝试构建一个同构反应应用程序。我使用express作为后端。我有一个带有App组件的静态路由器。我捕获任何请求并使用renderToString,如下所示:
(下面的代码不完整,可能有语法错误 - 没有通过IDE运行它)
server.jsx:
app.get("/*", (req, res) => {
const itemIDs =
['myFirstItemID', 'mySecondItemID', 'myThirdItemID'] // fetched from DB
const renderedApp =
ReactDOM.renderToString(<StaticRouter> <App itemIDs=itemIDs /> </StaticRouter>);
res.render("index", { renderedData: renderedApp });
res.end();
}
App.jsx - 仅限渲染方法
render() {
const renderedRoutes = this.props.itemIDs.map(itemID => (<Route path={itemID} render={() => <Item ItemID={itemID}/>} />)
);
return (
<Switch>
{renderedRoutes}
<Route component={ItemsContainer itemIDs=itemIDs} />
</Switch>
)
}
ItemsContainer.jsx - 仅限渲染方法
render() {
const ItemSummaries = this.props.itemIDs.map(itemId => <ItemPreview itemId={itemId}/>)
return (
<div>
{ItemSummaries}
</div>
)
ItemPreview.jsx - 仅渲染方法
render() {
return (
<div>
<Link to={"/" + this.props.itemId}>
<h2>an item</h2>
</Link>
</div>
)
Item.jsx - componentsndDidMount和render
componentDidMount() {
axios.get("/api/items?itemID=" + this.props.itemID)
.then((data) => this.state.itemData = data);
render() {
return (
<div>
//use itemData here
</Link>
</div>
)
Client.jsx - 提供给客户端(使用相同的App.jsx组件)
const MyRoutedApp = () =>
(<BrowserRouter>
<App />
</BrowserRouter>);
ReactDOM.hydrate(<MyRoutedApp/>, document.getElementById('root'));
我觉得我的做法有些不对劲,但我不确定是什么。我遇到的问题是:
因此,我发现解决第一个问题的一种方法是在初始索引页面响应中(在<script>
标记内)呈现路由,然后让App构造函数根据呈现的位置处理路由:
这是它在代码中的样子:
索引页面中的某个位置(EJS模板):
//
<script>const globalRoutes = <%- JSON.stringify(renderedRoutes) %> </script>
//
“/”请求处理程序:
var fetchedRoutes; //your routes
app.get("/*", (req, res) => {
var context = {};
const routedApp = ReactDOMServer.renderToString(
React.createElement(
StaticRouter,
{ location: req.url, context: context },
React.createElement(App, {routesData: fetchedRoutes})
)
);
res.render("index", { renderedData: routedApp, renderedRoutes: fetchedRoutes });
res.end();
});
App如何处理路线:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { routesData: this.isBrowser() ? globalRoutes : this.props.routesData }
}