Reputation: 2935
I am new to react and trying to create simple navigation which has two menu items (Dashboard and Users). But when I click on Users link it did not render that page content, but dashboard content getting hide. Someone please help me to resolve the issue.
App.js
import React, { Component } from 'react';
import Login from './pages/Login';
import { BrowserRouter as Router, Switch, Route, Link, Redirect, withRouter } from 'react-router-dom';
import { history } from './_helpers/history';
import { authenticationService } from './_services/authentication.service';
import Users from './pages/users/Users';
import Dashboard from './pages/Dashboard';
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentUser: null
};
}
componentDidMount() {
authenticationService.currentUser.subscribe(x => this.setState({ currentUser: x }));
}
logout() {
authenticationService.logout();
history.push('/login');
}
render () {
const { currentUser } = this.state;
return (
currentUser ? (
<Router>
<div id="wrapper">
<ul>
<li><Link to={'/'} className="nav-link" > <i className="fas fa-fw fa-tachometer-alt"></i> <span>Dashboard</span> </Link></li>
<li><Link to={'/users'} className="nav-link" > <i className="fas fa-fw fa-users"></i> <span>Users</span> </Link></li>
</ul>
<Switch>
<Route path='/' component={Dashboard} />
<Route path='/users' component={Users} />
</Switch>
</div>
</Router>
) : <Login />
);
}
}
export default App;
Dashboard.js
import React, { Component } from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { authenticationService } from '../_services/authentication.service';
import { history } from '../_helpers/history';
class Dashboard extends Component {
constructor (props){
super(props);
if (authenticationService.currentUserValue) {
history.push('/');
}
this.state = {
isPage: '/'
}
}
render (){
if(this.state.isPage == window.location.pathname){
return (
<div className="container">
dashboard
</div>
)
}else{
return '';
}
}
}
export default Dashboard;
Users.js
import React, { Component } from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { authenticationService } from '../../_services/authentication.service';
import { history } from '../../_helpers/history';
class Users extends Component {
constructor (props){
super(props);
if (authenticationService.currentUserValue) {
history.push('/');
}
this.state = {
isPage: '/users'
}
}
render (){
if(this.state.isPage == window.location.pathname){
return (
<div className="container">
users
</div>
)
}else{
return '';
}
}
}
export default Users;
Upvotes: 5
Views: 261
Reputation: 950
Remove this line.
if (authenticationService.currentUserValue) {
history.push('/');
}
this is redirecting you again and again to the same page.
Upvotes: 0
Reputation: 1296
According to the documentation, <Switch>
Renders the first child or that matches the location.
In your code you have:
<Route path='/' component={Dashboard} />
<Route path='/users' component={Users} />
The problem is that path='/'
actually matches any path, including /users
, because /users
starts with /
. So when the route is /users
, the Redirect component renders the Dashboard Route and stops looking for other routes.
To fix this, you could add the exact
prop to the /
Route. exact
means that /
will not match anything except paths that are exactly "/":
<Route exact path="/" component={Dashboard} />
<Route path="/users" component={Users} />
Now, if the path is /users
, the Dashboard Route no longer matches, and the Switch checks if the next Route matches, which it does!
Fixed & simplified example: https://codesandbox.io/s/lucid-leaf-fkgv9
Note that I have removed some code (like this.state.isPage == window.location.pathname
) which seemed to be checking if the route matches. You don't need to worry about this in your components, because React-Router takes care of all the routing for you!
Another solution would be to put the Users Route first so that it is checked first, but this can get messy if you have multiple Routes and want to keep them organized.
Upvotes: 0
Reputation: 1
I assume your ../../_helpers/history looks like that
import { createBrowserHistory } from "history";
export default createBrowserHistory();
You forget to pass history to Router as props, so other components do not know what is history
<Router history={history}>...</Router>`
Upvotes: 0
Reputation: 266
When using the <Switch>
component, it will render the first component (in order) that matches the path. Optionally you can put an exact prop on the route so it must match the path 100%.
Your <Dashboard>
component is being rendered, however your logic for returning an empty string if the path does not match is preventing you from seeing it. You can move the <Users>
route higher, or put an exact
prop on your routes.
I've created a small CodeSandbox
https://codesandbox.io/s/festive-worker-t7ly3
Upvotes: 1
Reputation: 931
In App.js component; make Switch
direct child of Router
; that will fix the issue. You can refactor your code like so:
<Router>
<Switch>
<div id="wrapper">
<ul>
<li><Link to={'/'} className="nav-link" > <i className="fas fa-fw fa-tachometer-alt"></i> <span>Dashboard</span> </Link></li>
<li><Link to={'/users'} className="nav-link" > <i className="fas fa-fw fa-users"></i> <span>Users</span> </Link></li>
</ul>
<Route path='/' component={Dashboard} />
<Route path='/users' component={Users} />
</div>
</Switch>
</Router>
Upvotes: 2
Reputation: 344
but dashboard content getting hide.
Can you elaborate on that? I'm not quite understanding what you mean.
The problem may lie with your use of react lifecycles.
authenticationService.currentUser.subscribe()
is set on componentDidMount() so only after the JSX gets mounted to the DOM. Your Users component is checking authenticationService.currentUserValue
on the constructor which runs first before it gets mounted. authenticationService.currentUserValue
maybe giving you a falsy which will kick you out to /
. Console log that value or place those inside a componentDidMount so it will only check after the mount.
constructor (props){
super(props);
this.state = {
isPage: '/users'
}
}
componentDidMount() {
if (authenticationService.currentUserValue) {
history.push('/');
}
}
Upvotes: 1