I'm using React/Redux/Router but this is really just a router question and one I can't seem to find the answer for. Essentially, I want my app to only kick in if the '#search' hash is present in the URL, otherwise don't do anything.
If I use something like the following I get an error (did not match any routes) when I go to the root URL '/'.
ReactDOM.render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="#search" component={HelloWorldContainer} />
</Router>
</Provider>,
document.querySelector('.body-wrap'),
);
Any help appreciated...
That's because you haven't provided a route for the root '/', which is the default entry point to a web application. I'm not sure why you wouldn't provide a route for the root '/' but React Router will continue to throw errors for routes it can't match. You can provide an entire component as a catch-all for routes that don't match what you've specified; like so:
<Route path='*' component={ErrorPage}/>
Also, a request to the route path='#search' must be exact to match. So a request to /#search123 will throw an error, unless you have the catch-all route above.
Related
I want to be able to serve a React app using React Router both on an Apache and NGINX server without having to change any default Apache/NGINX configs.
The problem is that the application will only be served when you access the root folder, as any sub path leads to a 404 (app.com/ works but not app.com/settings).
For the Apache server, I include a .htaccess file that automatically loads index.html if the requested resource is not found.
For NGINX as far as I understand there is no way to properly load the application in a sub-path unless you change the config file.
My solution for this would be to add the option in the app to store the Router path as a query string, instead of in location.pathname, something like app.com/?page=settings instead of app.com/settings.
Is there any way to add some sort of a middleware in the React router such that when accessing app.com/?page=settings the Router path will be set to /settings. Also, when the user navigates and the router should update the URL in the address bar, it should change it to app.com/?page=user/dashboard instead of app.com/user/dashboard.
I am looking for any solution that would allow the Router to work both with a path and with the path specified as a query string variable.
If needed, here is how my router looks:
<Router history={browserHistory}>
<Route path={BaseRoutes.Home} exact>
<Redirect to={BaseRoutes.Domains} />
</Route>
<Route path={[BaseRoutes.Stats, BaseRoutes.Settings, '/*']} component={SidebarMain} />
<div className={`content-area ${classes.content}`}>
<Switch>
<Route exact path={BaseRoutes.Stats} component={Stats} />
<Route exact path={BaseRoutes.Home} component={Domains} />
<Route exact path={BaseRoutes.Settings} component={Settings} />
</Switch>
</div>
</Router>;
Never mind, I realized I can just use HashRouter instead of Router for NGINX...
So, depending on whether the user's setting of having "pretty" URLs or hash based URLs I can either load the BrowserHistory Router or the HashRouter:
<Router history={browserHistory}> OR <HashRouter>
To switch between them I did:
let SupportedRouter: React.ElementType = HashRouter;
if (MY_CONDITION) {
SupportedRouter = Router;
}
// Render
<SupportedRouter history={browserHistory}>
</SupportedRouter>
I had to cast them to React.ElementType, otherwise optionally passing history lead to TypeScript errors: https://github.com/microsoft/TypeScript/issues/28631#issuecomment-472606019
I have two routes, a base path and a customer route. The customer route takes a customerId parameter.
<HashRouter>
<Switch>
<Route path="/mapper/:mappingId/" exact component={Mapper}/>
<Route path="/" exact component={App} />
</Switch>
</HashRouter>
then in the react component I am calling it like this to navigate
window.open(`/customer/${customerId}`)
(updated, still doesn't work)
but when I navigate it just goes to the App component. I have to use HashRouter because the react app is wrapped in Electron. BrowserRouter works on the web
The url i get when i navigate is this:
http://localhost:3000/customer/ca023754-bb75-4f64-a19c-958525b53e12#/
I also tried adding backslash in Route, /customer/:customerId/, that didn't work as well
I have read How to use React Router with Electron? but it doesn't really work
I finally figured this out. Hashrouter expect the url to have "#/" after the basepath. so it should be window.open('#/customer/${customerId}')
I'm building an app with some relatively complex routing. The reason it's unusual is that I am animating both the route itself and using the route render method, rather than just calling the component.
So my code looks something like this inside App.js:
// Route 1
<CSSTransitionGroup>
<Route render=(
<CSSTransitionGroup>
// stuff
</CSSTransitionGroup>
)/>
</CSSTransitionGroup>
// Route 2
<CSSTransitionGroup>
<Route render=(
<CSSTransitionGroup>
// stuff
</CSSTransitionGroup>
)/>
</CSSTransitionGroup>
I'm calling this from index.js with:
<Router>
<Route render={({location}) => (
<App location={location} />
)}/>
</Router>
I need to add a "no match" route. Looking at the official docs I should be using the Switch method and then placing this route at the bottom. The problem is, I think, because I'm using lots of nesting and CSSTransitionGroup, this is not working. It appears that Switch depends on having Routes immediately listed in order to work.
So my question - how can I create a "page not found" route with this setup?
Any route that does not have a path will always match. Regardless of whether you're using a switch or not. The following should work fine. However when you put it is important. You'll need to place it with all the top level routes that are created.
<Router>
<Route render={({location}) => (
<App location={location} />
)}/>
</Router>
If you are finding that other routes are matching, i.e. the root route, you may need to use the exact keyword
I found a solution to this. I needed to move all of my routes inside one CSSTransitionGroup, and then place the Switch inside it, but also pass some location info to it:
<CSSTransitionGroup ...>
<Switch location={this.props.location} key={this.props.location.key}>
<Route ..>
</Switch>
</CSSTransitionGroup>
I'm trying to make a multilingual SPA with React and to rely on React-Router.
Here is a simplified version of the entry file:
// define the routes for each language ..
const InnerRoutes = (
<Route>
<IndexRoute page="home" component={InnerPage}></IndexRoute>
<Route path="(:page)" component={InnerPage}></Route>
</Route>
);
// define the routes for all the languages, using InnerRoutes ..
const AllRoutes = (
<Router history={browserHistory}>
<Route path='/' component={App} language="bg">
{InnerRoutes}
<Route path="en" language="en">
{InnerRoutes}
</Route>
</Route>
</Router>
);
// and render our app ..
ReactDOM.render(
AllRoutes,
document.getElementById('app')
);
So, I have the App top-level component and the InnerPage component.
The issue is:
When navigation change happens - InnerPage updates and (eventually) re-renders.
Inside InnerPage:
I have access to the requested page via the page property.
Unfortunately - I don't have access to the language property.
And that's why InnerPage can't pull the data from an end point - it knows the page, but not the language.
The router passes a routes prop to all route components, which is the set of matched routes. For example, on /, it would look something like this: [{ path: '/', language: 'bg'}, { }, { page: 'home' }].
So, depending on how you want to deal with the cases of having none or multiple languages declared by different matched routes, you can do something like this:
const lang = this.props.routes.reduce((lang, route) => {
return route.language || lang;
}, defaultLang);
which would prioritize the language given by inner routes.
Looking at your route config, there are two more things I should mention:
In your InnerRoutes, the page values for <IndexRoute page="home" ... /> and <Route path="(:page)" ... /> are exposed differently. The former is a prop on a route (like language) and can be accessed via this.props.route.page, while the latter is a URL param (this.props.params.page).
The English <IndexRoute> is not reachable, because the Bulgarian :page route comes before and matches as well. You can fix this by moving the English routes up.
Here's a jsbin demonstrating the points I mentioned: http://jsbin.com/siqake/5/edit?js,output
I have a particular situation where I would like to load a different route rather than the initial request route while keeping the app universal/isomorphic.
So I have some routes like so
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="potato" component={Potato}/>
<Route path="apple" component={Apple}/>
</Route>
</Router>
On the initial request of / the server decides based on some other information elsewhere what other route should be loaded instead, ie the apple route should be rendered instead but the url on the front end should remain /
At first this is quite trivial as you can just change the url provided to match
match({ routes, location: url }, (error, redirectLocation, renderProps) => {
However, the client first displays correctly then a few seconds after it loads the original request route rather than what the server decided.
It would display an error like this
Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
This makes sense as I told the server to render the /apple when the / route was hit. But when it gets to the client side it goes 'Um the route is / but the markup is showing something different to what should be there.
So is there anyway I can fool the client that everything is well and correct?
One solution is just do a 301 redirect but this means the client side
will end up showing /apple rather than just / in the url
I'd like to avoid a 301 for SEO and to keep the initial url route that the user typed
Any solution for this bonkers request?
I'm using
react:15.0.2
react-router: 2.4.0
react-redux:4.1.2
redux: 3.1.2
You can define the routes on the server before calling match and let the client pick them up on the client.
Something like this on the server:
function getRoutes(something) {
if (something === 'apple') {
return (
<Route path="/" component={Apple}>
<Route path="potato" component={Potato}/>
</Route>
);
}
return (
<Route path="/" component={App}>
<Route path="potato" component={Potato}/>
<Route path="apple" component={Apple}/>
</Route>
);
}
const routes = getRoutes('apple');
<script dangerouslySetInnerHTML={{__html: `window.__INITIAL_ROUTES__ = ${routes}`}}></script>
<Router history={createMemoryHistory()}>
{routes}
</Router>
...and on the client:
const routes = window.__INITIAL_ROUTES__;
<Router history={browserHistory}>
{routes}
</Router>