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);
}
{
"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"
}
}
This is a potential server related issue. You probably got Apache 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]
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.
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>
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.
index.html
as you expected.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 '<'
.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/...
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With