1

I am using React Router. When i try to enter my interface by localhost:3000/Login; i am getting this error. "Invariant failed: Browser history needs a DOM". I googled everywhere but i couldn't find any solutions. I am sharing my codes, anyone to help??

my server.js file

import React from 'react';
import { StaticRouter } from 'react-router-dom';
import express from 'express';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import serialize from 'serialize-javascript';

import App from '$/containers/app';
import setupStore from '$/state/store';

const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
const server = express();

server
  .disable('x-powered-by')
  .use(express.static(process.env.RAZZLE_PUBLIC_DIR))
  .get('/*', (req, res) => {
    // Compile an initial state
    const preloadedState = { counter: 0 };

    // Create a new Redux store instance
    const store = setupStore(preloadedState);

    const context = {};

    // Render the component to a string
    const markup = renderToString(
      <Provider store={store}>
        <StaticRouter context={context} location={req.url}>
          <App />
        </StaticRouter>
      </Provider>,
    );

    // Grab the initial state from our Redux store
    const finalState = store.getState();

    if (context.url) {
      res.redirect(context.url);
    } else {
      res.status(200).send(
        `<!doctype html>
    <html lang="">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta charset="utf-8" />
        <title>Welcome to Razzle</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        ${
  assets.client.css
    ? `<link rel="stylesheet" href="${assets.client.css}">`
    : ''
}
        ${
  process.env.NODE_ENV === 'production'
    ? `<script src="${assets.client.js}" defer></script>`
    : `<script src="${assets.client.js}" defer crossorigin></script>`
}
    </head>
    <body>
        <div id="root">${markup}</div>
        <script>
          window.__PRELOADED_STATE__ = ${serialize(finalState)}
        </script>
    </body>
</html>`,
      );
    }
  });

export default server;

my app.js file

import React from 'react';
import Home from '$/components/pages/home';
import Login from '$/components/pages/login';
import Logout from '$/components/pages/logout';
import '$/css/app.css';

const { Route, Switch, BrowserRouter } = require('react-router-dom');

const App = () => (
  <BrowserRouter>
    <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/login" component={Login} />
      <Route exact path="/logout" component={Logout} />
    </Switch>
  </BrowserRouter>
);
export default App;

my client.js file

import React from 'react';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';

import setupStore from '$/state/store';
import App from '$/containers/app';

const store = setupStore(window.__PRELOADED_STATE__);
const { BrowserRouter } = require('react-router-dom');

hydrate(
  <BrowserRouter>
    <Provider store={store}>
      <App />
    </Provider>
   </BrowserRouter>,
  document.getElementById('root'),
);

if (module.hot) {
  module.hot.accept('./containers/app', () => {
    hydrate(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root'),
    );
  });
}
Furkan Arda
  • 11
  • 1
  • 3
  • This is caused because you are wrapping your router in another router in another router. Nesting routers causes this issue. You can see similar bug here: https://stackoverflow.com/questions/43058684/react-router-4-browser-history-needs-a-dom – zilijonas Jun 18 '19 at 06:30
  • @LiJonas So what do you suggest? Can you explain in example please? – Furkan Arda Jun 18 '19 at 06:51
  • You could try removing wrapper from your `hydrate()` call. – zilijonas Jun 18 '19 at 06:53
  • It didn't work. I think my problem is about server.js because my node screen warns me this: Invariant failed: Browser history needs a DOM Invariant failed: Browser history needs a DOM // Render the component to a string const markup = renderToString( – Furkan Arda Jun 18 '19 at 09:53

0 Answers0