React Router-浏览器历史记录需要dom

时间:2018-07-18 22:42:51

标签: javascript reactjs express react-router material-ui

我正在使用React.js并为我的应用程序表达。我正在尝试为该应用设置react-router-dom。

但是,当我尝试运行该应用程序时,收到警告:

Invariant Violation: Browser history needs a DOM
    at invariant (/home/jshen/playlistTracker/node_modules/invariant/invariant.js:40:15)
    at createBrowserHistory (/home/jshen/playlistTracker/node_modules/history/createBrowserHistory.js:49:27)
    at new BrowserRouter (/home/jshen/playlistTracker/node_modules/react-router-dom/BrowserRouter.js:46:197)
    at processChild (/home/jshen/playlistTracker/node_modules/react-dom/cjs/react-dom-server.node.development.js:2095:14)
    at resolve (/home/jshen/playlistTracker/node_modules/react-dom/cjs/react-dom-server.node.development.js:2061:5)
    at ReactDOMServerRenderer.render (/home/jshen/playlistTracker/node_modules/react-dom/cjs/react-dom-server.node.development.js:2380:22)
    at ReactDOMServerRenderer.read (/home/jshen/playlistTracker/node_modules/react-dom/cjs/react-dom-server.node.development.js:2354:19)
    at renderToString (/home/jshen/playlistTracker/node_modules/react-dom/cjs/react-dom-server.node.development.js:2726:25)
    at handleRender (/home/jshen/playlistTracker/dist/server.js:755:41)
    at Layer.handle [as handle_request] (/home/jshen/playlistTracker/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/jshen/playlistTracker/node_modules/express/lib/router/index.js:317:13)
    at /home/jshen/playlistTracker/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/jshen/playlistTracker/node_modules/express/lib/router/index.js:335:12)
    at next (/home/jshen/playlistTracker/node_modules/express/lib/router/index.js:275:10)
    at expressInit (/home/jshen/playlistTracker/node_modules/express/lib/middleware/init.js:40:5)
    at Layer.handle [as handle_request] (/home/jshen/playlistTracker/node_modules/express/lib/router/layer.js:95:5)

App.jsx

import React, {Component, Fragment} from 'react';
import {BrowserRouter, Switch, Route } from 'react-router-dom'
import { NavBar } from './layouts'
import Main from './main'


class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      currentUser: {name: "testUser"},
      favourite: [],
      playlist: []
    };
  }

  render() {
    return (
      <BrowserRouter>
        <NavBar>
          <Switch>
            <Route exact path ="/" render={
              () => <div> hello </div>
            }/>
          </Switch>
        </NavBar>
      </BrowserRouter>
    )
  }

}

export default App;

server.js

import express from 'express';
import React from 'react';
import App from '../client/App.jsx';

import { renderToString } from 'react-dom/server'
import { SheetsRegistry } from 'react-jss/lib/jss'
import JssProvider from 'react-jss/lib/JssProvider'
import {
  MuiThemeProvider,
  createMuiTheme,
  createGenerateClassName,
} from '@material-ui/core/styles'

const app = express();
const port = 3000;

// This is fired every time the server side receives a request.
app.use(handleRender);
app.listen(port);

// inject our initial component HTML and CSS into a template to be rendered on the client side.
function renderFullPage(html, css) {
  return `
    <!doctype html>
    <html>
      <head>
        <title>Material-UI</title>
      </head>
      <body>
        <div id="root">${html}</div>
        <style id="jss-server-side">${css}</style>
      </body>
    </html>
  `;
}

// When rendering, we will wrap App, our root component, inside a JssProvider and MuiThemeProvider 
// to make the sheetsRegistry and the theme available to all components in the component tree.
// Render the initial HTML of our component before we send it to the client side. 
// To do this, we use ReactDOMServer.renderToString().
function handleRender(req, res) {
  // Create a sheetsRegistry instance.
  const sheetsRegistry = new SheetsRegistry();

  // Create a theme instance.
  const theme = createMuiTheme({
    palette: {
      primary: {
        light: '#757575',
        main: '#a4a4a4',
        dark: '#494949',
        contrastText: '#ffffff',
      },
      secondary: {
        light: '#263238',
        main: '#a4a4a4',
        dark: '#494949',
        contrastText: '#ffffff',
      },
      // accent: red,
      // type: 'light',
    },
  });

  const generateClassName = createGenerateClassName();

  // Render the component to a string.
  const html = renderToString(
    <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}>
      <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
        <App />
      </MuiThemeProvider>
    </JssProvider>
  )

  // Grab the CSS from our sheetsRegistry.
  const css = sheetsRegistry.toString()

  // Send the rendered page back to the client.
  res.send(renderFullPage(html, css))
}

无法弄清我所缺少的。我认为这可能是由于服务器端的某些原因造成的,但无法弄清楚。

我读到它可能是由于历史记录组件引起的,但是,我看到了一些示例仅与BrowerRouter一起使用的示例。(例如https://github.com/jsmegatools/React-online-course/tree/master/Lesson-2

谢谢!

2 个答案:

答案 0 :(得分:0)

您需要正确设置。两者互不相同。 React是客户端应用程序,而Express是服务器应用程序。

看看Sandeep Raveesh's post,然后尝试boilerplate。它可以帮助您理解它。

答案 1 :(得分:0)

@Tholle的回答帮助我解决了这个问题。

https://reacttraining.com/react-router/web/guides/server-rendering