(同构)路由和基于ajax的反应组件的后端呈现

问题描述 投票:1回答:1

我正在尝试构建一个同构反应应用程序。我使用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'));

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

  • ItemID仅在服务器中用于生成路由。一旦应用程序在客户端可用,我就不再有路由,因此BrowserRouter不起作用。我可以使用ajax获取路由,但是这会导致在我拥有所需数据之前进行初始渲染,这导致无论我在哪个URL,都会看到几帧的ItemsContainer(默认路由)。
  • 我有什么选择来renderToString一个组件,它依赖于componentDidMount中的ajax来决定它的render()内容(Item.jsx)?
  • 最后但并非最不重要的 - 这实际上是一个好方法吗?
javascript reactjs react-router-v4 isomorphic-javascript
1个回答
0
投票

因此,我发现解决第一个问题的一种方法是在初始索引页面响应中(在<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 }
    }
© www.soinside.com 2019 - 2024. All rights reserved.