首页 > 解决方案 > (同构)路由和基于ajax的react组件的后端渲染

问题描述

我正在尝试构建一个同构反应应用程序。我使用 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 - componendDidMount 和渲染

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'));

我觉得我的方法有些不对劲,但我不确定是什么。我遇到的问题是:

标签: javascriptreactjsreact-router-v4isomorphic-javascript

解决方案


因此,我发现解决第一个问题的一种方法是在初始索引页面响应中(在<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 }
    }

推荐阅读