I have tried following the answer on this question but to no avail.
I am trying to use react router and nested routes to render different layouts depending on the configuration of the router.
But the route with path="/" always shows regardless of the URL that is present.
Here is the router that I am using.
<Route component={App}>
<Route component={LayoutOne}>
<Route path="/" component={ComponentOne}/>
</Route>
<Route component={LayoutTwo}>
<Route path="category" component={ComponentTwo}/>
</Route>
</Route>
And here is the App file that I use to map the dispatch to the props, and connect.
function mapStateToProps(state, ownProps){
return{
exampleProp: state.exampleProp,
};
}
function mapDispatchToProps(dispatch){
return bindActionCreators(actionCreators, dispatch);
}
const App = connect(mapStateToProps, mapDispatchToProps)(MainLayout);
export default App;
Here is the main layout MainLayout as seen above.
export default class MainLayout extends Component {
render(){
<div className="main-layout">
{this.props.children}
</div>
}
}
LayoutOne and LayoutTwo(has been omitted for brevity) are simple class rappers as follows.
export default class LayoutOne extends Component{
render(){
return(
{this.props.children}
)
}
}
And here the ComponentOne and ComponentTwo respectively are just simple components.
My problem is that only ComponentOne renders regardless of what URL is present.
How do I fix this issue so that I could use nested routes as shown above?
Your help would be much appreciated.
If you need any additional information, please ask and I will do my best to update the question with the required information.
Thanks.
The problem you're having is that the index route, i.e. '/', is being matched first in your route tree, and because it matches any route, it is the route that gets rendered every time.
You can fix this by moving the Route with path="category" above the one with path="/". This way the more detailed route option gets checked first. I would also recommend changing path="category" to path="/category" just for clarity's sake as both are root level routes.
Changing your routes to look like this should fix your problem
<Route component={App} path="/">
<Route component={LayoutOne} path="">
<Route component={ComponentOne}/>
</Route>
<Route component={LayoutTwo} path="category">
<Route component={ComponentTwo}/>
</Route>
</Route>
Related
I edited my questions as I realized it was not clear:
Visit https://codesandbox.io/s/dry-glitter-7lk9i?fontsize=14&hidenavigation=1&theme=dark
I was using states for the purpose of having the following structure:
Header
BODY (CONTENT)
Footer
Onclick actions or other events, I used states to hide components and show components in the body content.
I then wanted to be able to access a certain page by url ex (localhost:3000/privacy) So I'm looking to use Router to do so.
When I do a switch command, it does not hide my main component and show the switch, rather it shows both of them. How do I get the UI to react to the way I was initially coding?
You should wrap LandingPage component inside Route. Please check below for detail.
App.js
export default function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/">
<Landingpage />
</Route>
<Route exact path="/businessregister">
<BusinessRegister />
</Route>
</Switch>
</div>
</Router>
);
}
Baymax has the correct answer but answering to explain a bit more.
The Switch component renders routes exclusively; it matches and returns the first matched route component. The Landingpage component iss always being rendered by the router no matter what the path is.
By moving Landingpage onto a route you can conditionally render it based upon the current path. Placing it last and not specifying a path means that if any route declared before it is matched and returned then it won't render, but if no routes match, then the Landingpage component route will match all paths and render.
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route exact path="/businessregister">
<BusinessRegister />
</Route>
<Route component={Landingpage} /> // <-- render if nothing matches above
</Switch>
</div>
</Router>
);
}
I've been following this tutorial for creating a react project. The tutorial led to creating multiple react components that have a simple sample text within them. This would allow for the testing of the react-router-dom.
example of the simple component, all other components are similar.
import React, { Component } from 'react'
export default class Cart extends Component {
render() {
return (
<div>
<h3>Hello From Cart</h3>
</div>
)
}
}
The components are displayed using a react router which switches the displayed component depending on the url
class App extends React.Component {
render() {
return (
<React.Fragment>
<NavBar/>
<Switch>
<Route path="/details" Component={Details} />
<Route path="/cart" Component={Cart} />
<Route path="/" Component={ProductList} />
<Route Component={Default} />
</Switch>
</React.Fragment>
);
}
}
Furthermore to avoid confusion, my browser router is encapulating my App component from the index.js
ReactDOM.render(
<Router>
<App />
</Router>
, document.getElementById('root'));
When I navigate to the /cart url on my local host these are my results.
What should be displayed:
https://imgur.com/fZw5QnP.png
However, what is displayed is:
https://i.imgur.com/F1O07Y8.png
Please help me fix this issue, thank you.
I realized my error, I had "Component={}" within the Route, when it was supposed to be "component={}" (lowercase "c"). I'm posting this for all those, who have the same issue.
I'm trying to build a React App, this is the first time i'm working with react and so i don't know how to troubleshoot this. Basically what i need is to create routes for a link, let's say these are the following links.
/car
/car/sedan
/car/coupe
i have setup routing as so.
car.js
import React from 'react'
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'
import CoupeCar from './coupecar'
import SedanCar from './sedancar'
class Car extends React.Component {
constructor(props){
super(props);
}
render () {
return (
<div className="main_elem_container">
<Router>
<Switch>
<Route path="/car" component={Car} />
<Route exact path="/car/sedan" component={SedanCar} />
<Route exact path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
</div>
);
}
}
const Car = () => (
<p>I'm a Car</p>
)
export default Car;
And the routing works i can visit /car/sedan and /car/coupe when i'm browsing through the navigation from /car but i cannot visit /car/sedan when im at the /car/coupe page and vice-versa.
The navigation just gets stuck and doesn't load, please let me know on how i can fix this i've even tried many options but all of them give me this result, at least if i knew how to debug this it'll be better, thanks.
I don't know how your setup works partially, it should not with this config. What you need is:
<Router>
<Switch>
<Route exact path="/car" component={Car} />
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
So, if only when you hit /car your Car component renders. For /car/sedan and /car/coupe you will see the related components. If you don't use exact for /car, /car/sedan and /car/coupe will render Car component no matter what.
Also, do not use same component names. You have two Car components. Rename the container something else, App maybe?
try this, the exact path should be placed as last option
<Router>
<Switch>
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
<Route exact path="/car" component={Car} />
</Switch>
</Router>
I have two environments: 'Administrador' and 'Alumno'. I would like to know how I can do so such that an 'Administrador' user can not access the routes of an 'Alumno' user and vice versa. I am using React-Router 2.4.0. Is this possible with this technology? I am new to ReactJS (I use version 15.4.2).
Another question: Would it be convenient to update to the new version and transpile all my routes?
Here are my routes:
<Router history={browserHistory}>
<Route path="/" component={NotFound}/>
<Redirect from="/alumno" to="/alumno/inicio"/>
<Redirect from="/administrador" to="/administrador/inicio"/>
<Route path="/" component={App}>
<Route path="alumno" component={AppAlumno}>
<Route path="inicio" component={Alumno_Inicio}/>
<Route path="nueva_incidencia" component={Alumno_NuevaIncidencia}/>
<Route path="mis_incidencias" component={Alumno_MisIncidencias}/>
</Route>
<Route path="administrador" component={AppAdministrador}>
<Route path="inicio" component={Administrador_Inicio}/>
<Route path="nueva_incidencia" component={Administrador_NuevaIncidencia}/>
<Route path="incidencias_recibidas" component={Administrador_IncidenciasRecibidas}/>
<Route path="incidencias_recibidas/nuevo_informe" component={Administrador_NuevoInforme}/>
<Route path="informes" component={Administrador_Informes}/>
<Route path="informes/nueva_respuesta_informe" component={Administrador_NuevaRespuestaInforme}/>
</Route>
</Route>
</Router>
Thank you.
So to answer your questions:
For the first question:
Yes, limiting access to routes is possible using this technology. There are several ways to do it, the simplest way to do it is to check for identity of the user in the componentWillMount() function. It may look something like this, depending on how you identify your user as an Administrador or an Alumno:
import React from 'react';
import { browserHistory } from 'react-router';
class YourComponent extends React.Component{
componentWillMount(){
//If user is an Alumno, throw them to '/some/path'
if(this.state.isAlumno)
browserHistory.push('/some/path');
}
render(){
return <YourJsx />;
}
}
export default YourComponent;
This way you don't need to change your routes.
You can also achieve the same functionality by having a higher order component (HOC) that returns the component you want to limit access to. If you want to go the HOC way, you first need to create a new component that may look like this:
import React from 'react';
import {browserHistory} from 'react-router';
//This function receives the Component that only some user should access
function RequireAdmin(ComposedComponent){
class Authenticated extends React.Component {
componentWillMount(){
if(this.state.isAlumno)
browserHistory.push('/some/path');
}
render(){
return <ComposedComponent />;
}
}
//Return the new Component that requires authorization
return Authenticated;
}
Then, the route that you want to limit access to would look like this:
<Route path="administrador" component={RequireAdmin(AppAdministrador)}>
...
</Route>
Personally, I prefer the second way. It makes it clearer on the route which routes require what kind of authorization, and separates the components from the authorization.
To answer the second question:
It depends on how much of a hassle it would be. I'd certainly recommend learning the new API react-router v4, but I don't think it would be worth it to update an already built project, specially one with as many routes as yours.
Hope this helps! Buena suerte con React.
I have a component called Header which exists across all routes, while the rest of the app changes. So to accomplish this, my main render code looks about like this (using ES6):
render(){
return (
<div>
<Header></Header>
<Router>
<Route path="/" component={Home} />
<Route path="/details/:id" component={Details} />
</Router>
</div>
);
}
The challenge is that the contents of the <Header> should vary slightly depending on the route, for example a unique title per route.
How can this be achieved?
Thanks for all the great answers! Still mulling them over.
To throw another solution into the mix, I found that I can actually put arbitrary properties on the Route, so I added title:
<Route title="My Title" component={App} />
And I re-shuffled around my route hierarchy to include the header in Router (in the top-level Route component instead of outside any route as before), so my main render code looks like this:
<Router>
<Route component={App}>
<Route path="/" component={Home} title="Home" />
<Route path="/detail/:id" component={Detail} title="Details" />
</Route>
</Router>
And my App contains the header and is passed the current route's title:
class App extends React.Component {
render(){
var route = this.props.routes[this.props.routes.length - 1];
return (
<div>
<Header title={route.title} />
{this.props.children}
</div>
)
}
}
But I can't say this is the best solution. I do like that I can just put title on each route now, but I worry about the coupling and the way I have to extract the properties from the routes array.
This is a good use case for flux. You have route handlers that create an action when they mount. This action goes into the HeaderStore. The Header component listens to the Header store and renders based on it.
You can see an example of this here:
CurrentBoardStore holds the current page info
BoardPage updates the store when it mounts/updates
SubBoardHeaderWrapper renders the header with data from CurrentBoardStore
The way I do it (I'm pretty sure there is a better way, but this might help you out) looks like the following:
index.js
// define routes
const routes = (
<Route component={App} path="/">
<IndexRoute component={Home} />
<Route path="/" component={Home} />
<Route path="/details/:id" component={Details} />
</Route>
);
ReactDOM.render(<Router>{routes}</Router>, document.getElementById('your_id'));
App.js
render() {
return (
<div>
<Header routerProps={this.props.children} />
{this.props.children}
</div>
);
}
Header.js
componentWillReceiveProps(nextProps) {
// Get access to the pathname, it contains a string like "/details/"
console.log(nextProps.routerProps.props.location.pathname);
}
instead of putting header there.. put the header in a layout component. each view should use the layout component and you can pass whatever you want the header to be.
export class Layout extends React.Component{
render() {
return <div>
<Header title={this.props.title} />
{this.props.children}
</div>
}
}
all of your views can use this same component like so
export class SomeComponent extends React.Component{
render() {
return <Layout title="Some Component Title">
<div>my elements here</div>
</Layout>
}
}
NOTE: the beauty of using something like this, is you can set up any other default messaging like for instance lets say you want to have a flash message appear... someone clicks on something and you want a message to say 'You've successfully registered!' (in this example). You can include your flash messaging in the layout and simply dispatch an event to show the message. This can be done with modals too and really whatever your app requirements are :)