React router not working after building the app
Asked Answered
B

12

28

I am new to react and react-router. The app is created using create-react-app. I need to implement routing in my app with two main pages. I have tried many options and finally made it work with the following code.

This code works fine during development. But after building the app, its not working properly. The route to 404 page is only getting displayed. Please help me resolve this.

<Router history={browserHistory}>
  <Route component={Root}>
    <IndexRoute component={App} />
    <Route path="/" component={App} />
    <Route path="/sna/:country" component={SNA} />
    <Route path="*" component={FourOFour}/>
  </Route>
</Router>

I have used browserHistory to enable navigation on changing a dropdown using below code.

selectCountry(event){
    var value = event.target.value;
    browserHistory.push('/sna/' + value);
}

package.json

  {
  "name": "my-app",
  "version": "0.1.0",
  "homepage": "./",
  "private": true,
  "dependencies": {
    "bootstrap": "^3.3.7",
    "react": "^15.4.2",
    "react-addons-update": "^15.4.2",
    "react-bootstrap": "^0.30.8",
    "react-data-grid": "^2.0.24",
    "react-dom": "^15.4.2",
    "react-router": "^2.6.0"
  },
  "devDependencies": {
    "react-scripts": "0.9.5"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
Babb answered 10/4, 2017 at 13:33 Comment(4)
Without knowing your build + server setup up it is hard to give you any help. Is your development enviroment and the production enviroment the same? Meaning, are you using the same server (config) to host your app?Upperclassman
@SebastianSebald i have created app using create-react-app. The package.json contents are also added to question. Please let me know if you need more info.Babb
That helps a lot. What server are you using to host the build result? Does it supporting push?Upperclassman
I want to share the package with customer which he can open locally.(Similar to usual UI code: HTML + JS). Also, I don't think the issue is because of push method. Because blank page is displayed on app loading. It should ideally open the page in App component. Instead, its being routed to my custom 404 page.Babb
B
21

After getting stuck on react-router for a couple of days, I read the documentation in React Training. Then I followed the quick start steps and modified it to satisfy my requirements.

import {
  HashRouter as Router,
  Route,
  } from 'react-router-dom';

  <Router>
    <div>
      <Header />
      <Route exact path="/" component={Content} />
      <Route path="/:country" component={SnaContent} />
      <Footer />
    </div>
  </Router>

This have fixed the issue for now. Hope its helpful for others who faced similar issue.

Babb answered 17/4, 2017 at 6:55 Comment(2)
I had similar issue when I deployed my React app to Firebase Hosting. I found out that the issue was actually not with the react-router. The issue was with the web hosting service we use. We would need to indicate the default html file that we want to render, which is the index.html.Tigrinya
Fix for me was using HashRouter instead of BrowserRouter.Silas
J
44

This is a potential server related issue. You probably got a web server running and it is listening on :80.

For Apache server:

Make sure your Apache server redirects every request to index.html file. Make sure the following code is present in .htaccess

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
Jenevajeni answered 31/10, 2019 at 18:26 Comment(0)
B
21

After getting stuck on react-router for a couple of days, I read the documentation in React Training. Then I followed the quick start steps and modified it to satisfy my requirements.

import {
  HashRouter as Router,
  Route,
  } from 'react-router-dom';

  <Router>
    <div>
      <Header />
      <Route exact path="/" component={Content} />
      <Route path="/:country" component={SnaContent} />
      <Footer />
    </div>
  </Router>

This have fixed the issue for now. Hope its helpful for others who faced similar issue.

Babb answered 17/4, 2017 at 6:55 Comment(2)
I had similar issue when I deployed my React app to Firebase Hosting. I found out that the issue was actually not with the react-router. The issue was with the web hosting service we use. We would need to indicate the default html file that we want to render, which is the index.html.Tigrinya
Fix for me was using HashRouter instead of BrowserRouter.Silas
S
13

Edit:

The best way to do it is using the public URL where it will be deployed as the basename prop in the Router component. It could also be something like PUBLIC_URL=myproject, and it would make the build assuming the app is served at https://<domain-name>/myproject/index.html.

<Router basename={process.env.PUBLIC_URL}>
...
</Router>

Old answer:

First of all, this is not an issue with React Router. Notice that in your package.json, you have:

  "homepage": "./",
  "private": true,

The short answer is, if you change the value of "homepage" and make it "", or the URL of the homepage of the site where it is actually deployed, it will work directly.

"homepage": "",

OR

"homepage": "mysite.com/",

Here's why I think that works, in detail:

If you now use react-scripts build, it creates a file - build/index.html which imports JS files like <script src="./static/js/main.9ea6b007.chunk.js">.

Now, when you're using react-router, you ideally want to route all requests to build/index.html. So you may build a proxy server to serve your index.html and static files as follows (using Express.js):

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(express.static(path.join(__dirname, 'build')));

app.use('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'build/index.html'));
});

app.listen(process.env.PORT || 3000, () => console.log(`Running on PORT ${process.env.PORT || 3000}`));

Now you see that all your requests - except the ones for static files - return the index.html file. So, all your JS and CSS files will be returned when you request /static/js/main.9ea6b007.chunk.js. Notice how that's different from what is in your index.html source? The src in the index.html tries to request from ./static/..., and the . is interpreted as the current route.

So let's say you were to visit localhost:3000/abcd expecting your desired page to show up. Let's examine what happens here.

  • You get the index.html as you expected.
  • The index.html tries to request ./static/..., which translates to localhost:3000/abcd/static/..., whereas you wanted it to be localhost:3000/static/.... And anything that is not /static is going to return the same index.html, so even the JS files return the same page resulting in a console error Uncaught SyntaxError: Unexpected token '<'.
  • If you go to your browser Devtools and check out the sources, all your JS and CSS files would have the same content as index.html.

Therefore, the homepage in your package.json is used in the index.html as a prefix to all static files, in the form <homepage>/static/.... Hence it needs to be "" so that the requests are to /static/... or "mysite.com/", so that the requests are to mysite.com/static/....

Stormy answered 17/5, 2020 at 11:58 Comment(2)
Great man! Adding a "homepage" variable with URL, <Router basename={process.env.PUBLIC_URL}> and .htaccess file to force all requests to index.html file fixed my issue. Thank youFernery
Hey the "homepage": "", thing worked for me, thanks so much!Saida
T
10

I initially had the similar issue when I deployed my React app on Firebase Hosting.

It turned out that the issue was actually not with the react-router, as suggested by the poster of the accepted answer. HashRouter would append the /#/ in front of our URL, which doesn't look really pretty, no matter what.

I found out that the issue was with the web hosting service we use. We would need to indicate the default HTML file that we want to render, which is the index.html.

This happens because our hosting service provider (be it Amazon's S3 / Apache / Google Cloud Platform (GCP)'s App Engine / Firebase Hosting, etc) doesn't know which HTML file to render if a URL other than the default URL (https://www.link_to_your_website.com) was given. For instance, it won't be able to recognise https://www.link_to_your_website.com/login.

In Firebase Hosting, you would need to do:

"rewrites": [ {
    "source": "**",
    "destination": "/index.html"
}]

In Apache's .htaccess, you would need to do:

FallbackResource /index.html

Source: How to redirect an error 404 to home page with .htaccess?

These commands will tell them to render index.html no matter what because React-Route is going to dynamically update the HTML DOM's tree with the new React Elements.

Hope that those who faced this similar issue find this helpful.

Tigrinya answered 30/12, 2019 at 10:52 Comment(2)
For firebase hosting, where do I have to write those rewrites ? in which file ?Quicktempered
Hi @Hackytech! Sorry for the late reply. You have to add these rewrites in your freibase.json file. IIRC, firebase already automatically creates that for us in the newer version. I might be wrong since it has been a while since the last time I used firebase. Please check out the official doc: firebase.google.com/docs/hosting/full-config just in change if things have changed.Tigrinya
A
0

Try this, Define the routing in this way:

<Router history={browserHistory}>
   <Route path="/" component={Root}>
      <IndexRoute component={App} />
      <Route path="/sna/:country" component={SNA} />
      <Route path="*" component={FourOFour}/>
   </Route>
</Router>

Reason: You need to define the path to main route Root by path="/", and you don't need to define the separate route for App component, it's already your IndexRoute. Whenever you will navigate to /, it will render the App component.

Abort answered 10/4, 2017 at 13:40 Comment(1)
Thanks for the info. But once we build the app, your code didn't work. I don't understand why its routing to 404 page instead of App component.Babb
A
0

For me, the solution of Lili Susan V works for me with this code:

import { HashRouter as Router } from 'react-router-dom';
Alterant answered 27/2, 2020 at 7:11 Comment(1)
It does work. However, if you notice your URL, your URL will be appended by a pawn '#' sign. If you don't mind the aesthetics of the link, you could definitely use this method. However, it is not solving the root of the issue. I have explained the root of the issue in my answer above.Tigrinya
V
0

Faced similar issue recently, mine is a bit different issue and something not to deal with HashRouter or server config...

I was initially using render props method to render routed components like this

<Route
   path={route.path}
   render={(props) => (
     <route.component {...props} routes={route.routes} />
   )}
/>

and when I converted to render children method like this

<Route path={route.path} key={route.path} children={<route.component />} />

it worked

Thus my final router setup looks like this

const routerConfig = [
  {
    path: '/billing',
    component: ComponentA,
    linkName: 'BILLING',
  },
  {
    path: '/update-price',
    component: ComponentB,
    linkName: 'PRICE UPDATE',
  },
]

const MainPage = () => {
  return (
      <Switch>
        {routerConfig.map((route) => (
          <RouteWithSubRoutes key={route.path} {...route} />
        ))}
      </Switch>
  )
}

function RouteWithSubRoutes(route) {
  return <Route path={route.path} key={route.path} children={<route.component />} />
}

Viscose answered 8/9, 2020 at 4:15 Comment(0)
F
0

This issue can also arise if the rewrite mod isn't enabled for Apache. You can enable it by executing:

sudo a2enmod rewrite
Fabricate answered 23/11, 2021 at 19:14 Comment(0)
D
0

I tried couple of ways and following worked for me (for static builds in root folder or subfolder)

I had deployed my application in subfolder, I have followed this configuration

On Reactjs side

My dependency

package.json

"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",

Homepage key

"homepage": "/SUBFOLDER",

in index.js for routes

 <Router basename={"SUBFOLDER"}>

on Apache side

cd /etc/apache2/sites-available/

choose your configuration file

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName  DOMAINNAME
    DocumentRoot /var/www/html/DOMAINNAME/

 <Directory /var/www/html/DOMAINNAME/SUBDIRECTORY/>
        #Options -Indexes +FollowSymLinks
        #AllowOverride All

        Options -MultiViews
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ index.html [QSA,L]

</Directory>

Once you make necessary changes, check config and restart apache

sudo apache2ctl configtest
sudo systemctl restart apache2
Drucilladrucy answered 20/9, 2022 at 5:41 Comment(0)
O
0

A recent version of React uses <BroswerRouter>...<BrowserRouter> and so, here I found that <BrowserRouter basename={process.env.PUBLIC_URL}> ... All the routes here ... <BrowserRouter> work perfectly for Firebase hosting.

I do not know much more about React, just beginning to learn. So, in advance apologize if now working later.

Orosco answered 8/4, 2023 at 21:41 Comment(0)
K
0

It is a server related issue. Adding below code in server.js file worked for me.

app.get('*', function (req, res) {
    res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

Note: Add this to the end of the file .i.e after all the API calls For example

Killingsworth answered 7/3 at 20:43 Comment(0)
S
-1

I Faced the same issue and read multiple articles but couldn't find a perfect answer but the articles gave me a clear understanding on the problem. So, I decoded my problem in this way:

  1. React is a single-page app framework
  2. On load the web page loads the index.html
  3. From index, we load the [router]react-router-dom that matches the URL.
  4. Everything works perfectly in the localhost but doesn't work in the production as we build the app.
  5. There's nothing wrong until here, so it's a complete hosting service that we use.
  6. In my case, I used firebase hosting, and I've redirected all to build/index.html
  7. The problem solved!!
Scarper answered 23/8, 2020 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.