1
votes

I'm a beginner in React and stuck with some problem.I'm using server rendering and uses express as server and Getting an error message : Error: Invariant failed: Browser history needs a DOM. I have checked fro solutions from various sites and have applied their solutions but getting different errors when applying different solution. As earlier I was getting an error : TypeError: Cannot read property 'location' of undefined for this I changed Router to BrowserRouter by importing -import { BrowserRouter as Router } from 'react-router-dom and after that I'm getting the below error.


index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Route from 'react-router-dom';

import App from './components/App';

ReactDOM.hydrate(
 <Router><App /></Router> ,
  document.getElementById('mountNode'),
);



App.js

import React, { useState } from 'react';
import {Route,Switch,browserHistory} from "react-router-dom";
import { BrowserRouter as Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';


import HomePage from './HomePage';
import About from './About';
export default function App()
{

//const history = createMemoryHistory();
    return (
    <Router history={browserHistory}> 
        <Switch>
            <Route path="/" exact component={HomePage}/>
            <Route path="/about" component={About}/>  
        </Switch>
    </Router>
    );
}

error

Error: Invariant failed: Browser history needs a DOM
at invariant (C:\LMS-APP\node_modules\tiny-invariant\dist\tiny-invariant.cjs.js:13:11)
at Object.createHistory [as createBrowserHistory] (C:\LMS-APP\node_modules\history\cjs\history.js:273:16)
at new BrowserRouter (C:\LMS-APP\node_modules\react-router-dom\modules\BrowserRouter.js:11:13)
at processChild (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:2995:14)
at resolve (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:2960:5)
at ReactDOMServerRenderer.render (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3435:22)
at ReactDOMServerRenderer.read (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3373:29)
at Object.renderToString (C:\LMS-APP\node_modules\react-dom\cjs\react-dom-server.node.development.js:3988:27)
at C:\LMS-APP\src\server\/server.js:10:40
at Layer.handle [as handle_request] (C:\LMS-APP\node_modules\express\lib\router\layer.js:95:5)



package.json

{
  "name": "LMS-APP",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
   "dev-server": "nodemon --exec babel-node src/server/server.js --ignore dist/",
   "dev-bundle": "webpack -w -d"
  },
     "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.9.6",
    "@babel/node": "^7.8.7",
    "@babel/preset-env": "^7.9.6",
    "@babel/preset-react": "^7.9.4",
    "babel-loader": "^8.1.0",
    "express": "^4.17.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.2.0",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.11"
  },
  "devDependencies": {
    "babel-eslint": "^10.1.0",
    "eslint": "^7.0.0",
    "eslint-plugin-react": "^7.20.0",
    "eslint-plugin-react-hooks": "^4.0.2",
    "nodemon": "^2.0.4"
  }
}
1

1 Answers

0
votes

Since you are using express.js as a server, I believe you also need to configure your server.js code. As the error log on the bottom part tells the first file that was called was at C:\LMS-APP\src\server\/server.js:10:40.

In this website https://reacttraining.com/react-router/web/guides/server-rendering there is a "Putting it all together" section, you can follow and implement the right code in your server-side code also. Please do remember to adjust it to your code on the server.js since you are using express.js.

Also pay attention to the code example the website has. Like this block:

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

The code snippet above would be placed in your server.js file.

The <StaticRouter> component of React Router is needed to resolve that error about "Error: Invariant failed: Browser history needs a DOM".

server.get("*", (req, res) => {
  // Render the component to a string.
  const html = ReactDOMServer.renderToString(    
    <StaticRouter location={req.url} context={context}>
      <App />
    </StaticRouter>

  );
  const finalDocument =`<html>
                          <head>
                            <title>Your App Title</title>
                          </head>
                          <body>
                            <div id="root">${html}</div>
                          </body>
                         </html>
                        `;
    res.send(finalDocument);
  }
});

This would be the sample code you should have for your server.get() function. The server variable holds the express app.

If the error would still occur, you should change first argument in the server.get() function from server.get("/", ....) to server.get("*", ....).

The * asterisk signifies a wildcard which means any access to the server or the default URL would then be handled by your server-side, GET http://localhost:<port> as an example.