Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-router dynamic segments crash when accessed

I have a route configuration that looks like this (showing only the parts that I think may be relevant):

var React = require('react');  var Router = require('react-router'); var { Route, DefaultRoute, NotFoundRoute } = Router;  var routes = (     <Route handler={AppHandler}>         <DefaultRoute handler={HomeHandler}/>         <Route name='home' path='/home' handler={HomeHandler}/>         <Route name='settings' path='/settings/?:tab?' handler={SettingsHandler}/>         <NotFoundRoute handler={NotFoundHandler}/>     </Route> );  Router.run(routes, Router.HistoryLocation, function (Handler) {     React.render(<Handler/>, document.getElementById('application')); }); 

Now, on my Settings react file, I have the following:

var Settings = React.createClass({     mixins: [Router.State],   render: function() { ... } }); 

If I access the host.local/settings and log this.getParams() everything works fine and the file renders showing me Object {tab: undefined} in the console. But as soon as I try host.local/settings/user - where I expected the console to return something like Object {tab: 'user'} -, the whole thing crashes somewhere and just starts throwing Uncaught SyntaxError: Unexpected token < in the console.

React is still young and therefore the errors are rather vague in many situations.

I've followed the specifications provided on the Path Matching Guide and it seems pretty standard, so I can only assume it's a problem with react-router itself or am I missing something?


Update

tl;dr: It's not a problem with react-router.

Long version:

Apparently, it turns out the issue is not on ReactJS neither React-Router themselves. It involves mostly a bug on gulp-webserver (which I'm using for developing using proxies to connect separate projects running in parallel) and triggers an error when URLs are typed directly on the browser instead of being accessed through a link.

I did a test and it works fine when navigating, but crashes when accessed directly as described on this github issue, which basically renders my functional deeplink tests unviable, but should work when in production.


Update 2

tl;dr: It's not a problem with gulp-webserver either.

In my case, it was related to relative and absolute paths and not any issue with gulp-webserver as mentioned before. To be more specific, I had to make sure your script and CSS references were absolute so that it doesn't try to find them in the path you're typing in the URL.

e.g.:

You have two URLs: /settings and /settings/account. In that case, if you have your script inclusion in the fallback file being something like <script src="scripts/main.js"></script>, the server will return a 404 for it, since there's no file in /settings/scripts/main.js.

Dumb of me, but in case anyone else falls for that, I hope this helps.


like image 473
Alexandre Theodoro Avatar asked Jan 31 '15 15:01

Alexandre Theodoro


People also ask

Why we use BrowserRouter in react?

React Router is a standard library for routing in React. It enables the navigation among views of various components in a React Application, allows changing the browser URL, and keeps the UI in sync with the URL. Let us create a simple application to React to understand how the React Router works.

What is the difference between BrowserRouter and Router in react?

At the core of every React Router application should be a router component. For web projects, react-router-dom provides <BrowserRouter> and <HashRouter> routers. The main difference between the two is the way they store the URL and communicate with your web server. A <BrowserRouter> uses regular URL paths.

What is useParams react Router?

The useParams hook is one of the several hooks in React router. It has been available in React router since version 5. You can use it to retrieve route parameters from the component rendered by the matching route. You will explore the React Router useParams hook and how to use it in this article.

Does react Router cause Rerender?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.


2 Answers

Thanks for your analysis, it helped me to realize it wasn't an issue with React Router but my own paths.

I added <base href="/" /> into the <head> of my index.html and it worked (:

Edit for React Router 3:

Since early 2016, React Router will show a warning when you set <base>:

Warning: Automatically setting basename using <base href> is deprecated  and will be removed in the next major release. The semantics of <base href>     are subtly different from basename. Please pass the basename explicitly in the options to createHistory 

It's better to do something like this instead:

const history = useRouterHistory(createHistory)({     basename: '/' }); 
like image 141
Yangshun Tay Avatar answered Oct 07 '22 22:10

Yangshun Tay


I am not encountering the error that you're seeing. It seems like your code is all right, so it's probably something that you didn't paste.

giving the information, I've build a quick project according to your spec and here's my setup

'use strict';  var React           = require('react'),     Router          = require('react-router'),     AppHandler      = require('./pages/app.js'),     HomeHandler     = require('./pages/home.js'),     SettingsHandler = require('./pages/setting.js'),     NotFoundHandler = require('./pages/not-found.js'),      Route           = Router.Route,     NotFoundRoute   = Router.NotFoundRoute,     DefaultRoute    = Router.DefaultRoute,     Routes;  Routes = (     /* jshint ignore:start */     <Route handler={AppHandler}>         <DefaultRoute handler={HomeHandler}/>         <Route name='home' path='/home' handler={HomeHandler}/>         <Route name='settings' path='/settings/?:tab?' handler={SettingsHandler}/>         <NotFoundRoute handler={NotFoundHandler}/>     </Route>     /* jshint ignore:end */ );  Router.run(Routes, Router.HistoryLocation, function (Handler, state) {     React.render(<Handler/>, document.body); }); 

I'm skipping the home and not found since those are not the problem, here's my setup in settings.js

'use strict'; var React = require('react')     Router = require('react-router');  var Setting = React.createClass({      mixins: [Router.State],     componentDidMount: function() {         //console.log(this.getParams());     },      render: function() {         /* jshint ignore:start */         console.log(this.getParams());         return (             <div>this is setting</div>         );         /* jshint ignore:end */     }  });  module.exports = Setting; 

hope these will help

like image 33
Jim Avatar answered Oct 07 '22 20:10

Jim