I'm using React-router and it works fine while I'm clicking into link buttons, but when I refresh my webpage it does not load what I want.
For instance, I am into localhost/joblist and everything is fine because I arrived here pressing a link. But If I refresh the webpage I get: Cannot GET /joblist
By default It didn't work like this. Initially I had my URL: localhost/#/ and localhost/#/joblist and they worked perfectly fine. But I don't like this kind of url, so trying to erase that '#' I wrote:
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
This problem does not happen with localhost/, this one always returns what I want.
EDIT: This app is single-page, so /joblist don't need to ask anything to any server.
EDIT2: My entire router.
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="joblist" path="/joblist" handler={JobList}/>
<DefaultRoute handler={Dashboard}/>
<NotFoundRoute handler={NotFound}/>
</Route>
);
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
For React Router V4 Users:
If you try to solve this problem by Hash History technique mentioned in other answers, note that
<Router history={hashHistory} >
does not work in V4, please use
HashRouter
instead:Reference: https://reacttraining.com/react-router/web/api/HashRouter
The router can be called in two different ways, depending on whether the navigation occurs on the client or on the server. You have it configured for client-side operation. The key parameter is the second one to the run method, the location.
When you use the React Router Link component, it blocks browser navigation and calls transitionTo to do a client-side navigation. You are using HistoryLocation, so it uses the HTML5 history API to complete the illusion of navigation by simulating the new URL in the address bar. If you're using older browsers, this won't work. You would need to use the HashLocation component.
When you hit refresh, you bypass all of the React and React Router code. The server gets the request for
/joblist
and it must return something. On the server you need to pass the path that was requested to therun
method in order for it to render the correct view. You can use the same route map, but you'll probably need a different call toRouter.run
. As Charles points out, you can use URL rewriting to handle this. Another option is to use a node.js server to handle all requests and pass the path value as the location argument.In express, for example, it might look like this:
Note that the request path is being passed to
run
. To do this, you'll need to have a server-side view engine that you can pass the rendered HTML to. There are a number of other considerations usingrenderToString
and in running React on the server. Once the page is rendered on the server, when your app loads in the client, it will render again, updating the server-side rendered HTML as needed.In case, anyone is here looking for solution on React JS SPA with Laravel. The accepted answer is the best explanation of why such problems happen. As already explained you have to configure both client side and server side. In your blade template, include the js bundled file, make sure to use
URL facade
like thisIn your routes, make sure add this to the main endpoint where the blade template is. For example,
The above is the main endpoint for the blade template. Now add an optional route too,
The problem that happens is that first the blade template is loaded, then the react router. So, when you're loading
'/setting-alerts'
, it loads the html and the js. But when you load'/setting-alerts/about'
, it first loads on the server side. Since on the server side, there is nothing on this location, it returns not found. When you have that optional router, it loads that same page and react router is also loaded, then react loader decides which component to show. Hope this helps.For those who are using IIS 10, this is what you should do to make this right. Be sure that you are using browserHistory with this. As for reference I will give the code for the routing, but this is not what matters, what matters is the next step after the component code below:
Since the problem is IIS receives request from client browsers, it will interpret the URL as if it is asking for a page, then returns a 404 page since there is no available page. Do the following:
And it will now work fine.
I hope it helps. :-)