使用 react-router v4 和 express.js 进行服务器渲染

IT技术 javascript node.js reactjs express react-router
2021-05-19 19:50:03

我正在尝试使用最新版本的 react-router v.4 设置服务器端渲染。我遵循了本教程https://react-router.now.sh/ServerRouter

刷新浏览器时出现以下错误:Invariant Violation: React.Children.only expected to receive a single React element child。

我的routes.jsx文件:

export default () =>
  <div>
    <Header />
    <Match pattern="/" component={Home} />
    <Match pattern="/about" component={About} />
    <Miss component={NotFound} />
  </div>;

index.jsx 中我正在渲染应用程序

import  BrowserRouter from 'react-router';    
import Routes from './routes';

ReactDOM.render(<BrowserRouter> <Routes /> </BrowserRouter>, document.getElementById('app'));

现在作为服务器我使用express.js这是我的配置:

import  Routes  from '../routes';

server.use((req, res) => {
  const context = createServerRenderContext();
  let markup = renderToString(
    <ServerRouter location={req.url} context={context} > <Routes /> </ServerRouter>);
  const result = context.getResult();

  if (result.redirect) {
    res.writeHead(301, {
      Location: result.redirect.pathname,
    });
    res.end();
  } else {
    if (result.missed) {
      res.writeHead(404);
      markup = renderToString(
        <ServerRouter location={req.url} context={context}> <Routes /> </ServerRouter>);
    }
    res.write(markup);
    res.end();
  }
});

除了官方之外,我没有找到任何使用此版本的 react-routes 进行服务器渲染的教程。谁能帮助我我做错了什么?谢谢。

4个回答

解决了 !

第一个问题是我在<Routes />标签周围有空格

正确的解决方法:

<ServerRouter location={req.url} context={context}><Routes /></ServerRouter>);

第二个问题是<Header /> 在 routes.jsx 文件中包含的标签。

我有以下错误(不变违规:元素类型无效:需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:未定义。检查渲染方法StatelessComponent

文件 Header.jsx 包含以下代码行:

import Link  from 'react-router';

正确的解决方案:(我忘了放大括号):

 import { Link } from 'react-router';

最大的问题是<BrowserRouter>预计只有一个孩子,所以你应该把它的孩子包装在一个div. 这样做是为了使 React Router 与环境无关(你不能div在 React Native 中渲染 a ,所以 RR 期望你包含适当的包装器)。

export default () =>
  <BrowserRouter>
    <div>
      <Header />
      <Match pattern="/" component={Home} />
      <Match pattern="/about" component={About} />
      <Miss component={NotFound} />
    </div>
  </BrowserRouter>;

作为次要问题,您将 包含<BrowserRouter>在您的<App>组件中,因此它将在服务器上呈现。你不想要这个。只有<ServerRouter>应该在服务器上呈现。您应该<BrowserRouter>进一步向上移动客户端组件层次结构以避免这种情况。

// App
export default () =>
  <div>
    <Header />
    <Match pattern="/" component={Home} />
    <Match pattern="/about" component={About} />
    <Miss component={NotFound} />
  </div>;

// index.js
render((
  <BrowserRouter>
    <App />
  </BrowserRouter>
), document.getElementById('app'))

因为BrowserRouter在 上不存在react-router,请尝试安装并从中导入react-router-dom

我相信上面列出的答案已经过时了。截至今天,官方react-router文档建议对服务器端呈现的应用程序使用StaticRouter而不是ServerRouter

一个很棒的文档可以在这里找到