React-router urls don't work when refreshing o

2018-12-31 02:49发布

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);
});

28条回答
人气声优
2楼-- · 2018-12-31 03:22

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:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

Reference: https://reacttraining.com/react-router/web/api/HashRouter

查看更多
爱死公子算了
3楼-- · 2018-12-31 03:23

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 the run 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 to Router.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:

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

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 using renderToString 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.

查看更多
素衣白纱
4楼-- · 2018-12-31 03:23

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 this

<script src="{{ URL::to('js/user/spa.js') }}"></script>

In your routes, make sure add this to the main endpoint where the blade template is. For example,

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

The above is the main endpoint for the blade template. Now add an optional route too,

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

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.

查看更多
查无此人
5楼-- · 2018-12-31 03:23

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:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />    
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

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:

  1. Open IIS
  2. Expand Server then open the Sites Folder
  3. Click the website/application
  4. Go to the Error Pages
  5. Open the 404 error status item in the list
  6. Instead of the option "Insert content from static file into the error response", change it to "Execute a URL on this site" and add "/" slash value to the URL.

And it will now work fine.

enter image description here enter image description here

I hope it helps. :-)

查看更多
登录 后发表回答