1

そのため、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を使用したくありません。

何かご意見は?

4

1 に答える 1