react-router 4 - 浏览器历史记录需要一个 DOM [英] react-router 4 - Browser history needs a DOM

查看:56
本文介绍了react-router 4 - 浏览器历史记录需要一个 DOM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 react-router 4 进行服务器端渲染.我正在遵循此处提供的示例 https://reacttraining.com/react-router/web/guides/server-rendering/putting-it-all-together

I am trying server side rendering using react-router 4. I am following the example provided here https://reacttraining.com/react-router/web/guides/server-rendering/putting-it-all-together

根据服务器上的示例,我们应该使用 StaticRouter.当我按照示例导入时,我看到 StaticRouter 为未定义

As per the example on server we should use StaticRouter. When I import as per the example I am seeing StaticRouter as undefined

import {StaticRouter} from 'react-router';

在网上做了一些研究后,我发现我可以使用 react-router-dom.现在我的导入语句看起来像这样.

After doing some research online I found I could use react-router-dom. Now my import statement looks like this.

import {StaticRouter} from 'react-router-dom';

但是,当我运行代码时,我在浏览器中遇到了Invariant Violation: Browser history requires a DOM.

However when I run the code I am getting Invariant Violation: Browser history needs a DOM in the browser.

我的 server.js 文件代码

my server.js file code

....
app.get( '*', ( req, res ) => {
  const html = fs.readFileSync(path.resolve(__dirname, '../index.html')).toString();
  const context = {};
  const markup = ReactDOMServer.renderToString(
    <StaticRouter location={req.url} context={context} >
      <App/>
    </StaticRouter>
  );

  if (context.url) {
    res.writeHead(302, {
      Location: context.url
    })
    res.end();
  } else {
      res.send(html.replace('$react', markup));
  }
} );
....

还有我的 client/index.js 代码

And my client/index.js code

....
ReactDOM.render((
  <BrowserRouter>
    <App />
  </BrowserRouter>
), root);
....

<小时>

更新 v1将我的示例减少到最低限度,但仍然出现相同的错误.


Update v1 Reduced my example to a bear minimum and still getting the same error.

clientIndex.js

import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from '../App'

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

serverIndex.js

import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from '../App'

createServer((req, res) => {
  const context = {}

  const html = ReactDOMServer.renderToString(
    <StaticRouter
      location={req.url}
      context={context}
    >
      <App/>
    </StaticRouter>
  )

res.write(`
  <!doctype html>
  <div id="app">${html}</div>
`)
res.end()
}).listen(3000);

App.js

import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import routes from "./client/routes";
const App = ( ) => (
  <Router>
    <Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
  </Router>
)

export default App;

推荐答案

您需要使用不同的历史提供程序进行服务器端渲染,因为您在服务器上没有真正的 DOM(和浏览器的历史).因此,将 BrowserRouter 替换为 Router 和 app.js 中的备用历史记录提供程序可以解决该问题.此外,您不必使用两个包装器.您在 app.js 和 clientIndex.js 中使用了两次 BrowserRouter,这是不必要的.

You need to use different history provider for server side rendering because you don't have a real DOM (and browser's history) on server. So replacing BrowserRouter with Router and an alternate history provider in your app.js can resolve the issue. Also you don't have to use two wrappers. You are using BrowserRouter twice, in app.js as well as clientIndex.js which is unnecessary.

import { Route, Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';

const history = createMemoryHistory();

  <Router history={history}>
   <Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
  </Router>

您现在可以用 ConnectedRouter 替换 StaticRouter,它可以在客户端和服务器中使用.我使用以下代码在历史记录之间进行选择并将其导出以用于 ConnectedRouter 的历史记录.

You can now replace StaticRouter with ConnectedRouter which can be used both in client and server. I use the following code to choose between history and export it to be used in ConnectedRouter's history.

export default (url = '/') => {
// Create a history depending on the environment
  const history = isServer
    ? createMemoryHistory({
        initialEntries: [url]
     })
   : createBrowserHistory();
}

这篇关于react-router 4 - 浏览器历史记录需要一个 DOM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆