How to show/hide reactstrap navbar in Reactjs Redux application? - reactjs

I want to show/hide the navigation bar depending upon logged in status of the user. Once the user is authenticated, I store the access-token in local storage. I have tried to show/hide the navigation bar by checking if access-token exists or not. But it needs a hard refresh.
Please find the header component: /components/app-header.js
const AppHeader = () => (
<Navbar color="light" light expand="md">
<NavbarBrand href="/">TestBrand</NavbarBrand>
<Nav navbar>
<NavItem>
<Link className="lnk" to='/users'>Users</Link>
</NavItem>
</Nav>
<Nav className="ml-auto" navbar>
<NavItem>
<Link className="lnk" to='/logout'>Logout</Link>
</NavItem>
</Nav>
</Navbar>
)
The file which handles all the routes is as below (routes/index.js):
import React from 'react';
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';
import { AppHeader } from '../components';
export default () => (
<BrowserRouter>
<div>
{
localStorage.getItem('access-token') &&
<div>
<AppHeader />
</div>
}
<Switch>
<Route exact path="/users" component={Users} />
<Route exact path="/users/add" component={Users} />
<Route exact path="/users/:id" component={Users} />
</Switch>
</div>
</BrowserRouter>
)
The main App just contains the following code:
import React, { Component } from 'react';
import Routes from '../routes';
import '../style.css';
class App extends Component {
render() {
return (
<div>
<Routes />
</div>
)
}
}
export default App;
I do not want to refresh the page, as it defeats the very purpose of SPA. How can I achieve that?

Make Routes a stateful Component.
import React from 'react';
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';
import { AppHeader } from '../components';
class Routes {
this.state = {loggedIn: false}
componentDidMount() {
if(localStorage.getItem('access-token')) {
this.setState({loggedIn: true})
}
//attach an event listener to the window object for storage event.
$(window).on('storage',() => {
if(localStorage.getItem('access-token')) {
this.setState({loggedIn: true})
}
});
}
render() {
return (
<BrowserRouter>
<div>
{
this.state.loggedIn &&
<div>
<AppHeader />
</div>
}
<Switch>
<Route exact path="/users" component={Users} />
<Route exact path="/users/add" component={Users} />
<Route exact path="/users/:id" component={Users} />
</Switch>
</div>
</BrowserRouter>)
}
}
export default Routes;
After the component is mounted you are listening to localStorage updates. if local storage is changed it will update the state of the component as required.

Related

useParams() for none route components in ReactJS

Please go through my App.js
<Provider store={reduxStore}>
<Router basename={process.env.PUBLIC_URL}>
<Container>
<Navigation /> <----------------------------------- HERE
<div className="wrapper">
<Switch>
<PublicRoute exact path={PATHS.HOME} component={Home} />
</Switch>
</div>
<Footer/> <---------------------------------------- HERE
</Container>
</Router>
</Provider>
Navigation is use in all components so I added that component in App.js. For sure, this component has no route linked to it. BUT:
In Navigation and Footer, I want to use useParams().
Navigation.js
import React from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import { withRouter, useParams } from 'react-router-dom';
const Navigation = (props) => {
const { slug } = props;
return (
<>
<Navbar>
<Nav>
<Nav.Link>
Home
</Nav.Link>
</Nav>
</Navbar>
</>
);
};
export default withRouter(Navigation);
My current url:
localhost:3000/event/:slug
I do recieve props, but I could not find slug
try remove exact ?
<Switch>
<PublicRoute path={PATHS.HOME} component={Home} />
</Switch>

React Router Links getting Change but not the View

Hi I googled everywhere about my problem still no luck for me.
Here i attached my sample code.
import React from 'react';
import {
BrowserRouter,
Route,
Switch,
NavLink,
Redirect
} from "react-router-dom";
const Login = () => <div> Login Content <NavLink to ="/AppHome"> go to App</NavLink> </div>;
const Register = () => <div> Register Content </div>;
const AppHome = () => <div> Welcome to the App </div>;
class Authenticate extends React.Component {
render() {
return (
<>
<div>
<NavLink to={"/Login"}> Login </NavLink>
<NavLink to = {"/Register"} > Register < /NavLink>
</div>
<div>
<Switch >
<Route path={"/"} component={Login} />
<Route path={"/Login"} component={Login}/>
<Route path={"/Register"} component = {Register}/>
</Switch>
</div>
</>
);
}
}
class App extends React.Component {
render() {
return (
<BrowserRouter >
<Switch >
<Route path="/" component={Authenticate}/>
<Route path="/AppHome" component={AppHome}/>
</Switch>
</BrowserRouter>
)
}
}
export default App;
Here, In Localhost:3000 , i set Login Component as default to show. it shows the view but when clicking on the signup link, url only changing not the view. what am i done wrong?
You are trying to nest the routes, but in your case this seems unnecessary.
I would setup my routes like this without nested routing:
import React from "react";
import {
BrowserRouter,
Route,
Switch,
NavLink,
Redirect
} from "react-router-dom";
class App extends React.Component {
render() {
return (
<BrowserRouter>
<Authenticate />
<Switch>
<Route path="/" exact component={Login} />
<Route path="/Login" component={Login} />
<Route path="/Register" component={Register} />
<Route path="/AppHome" component={AppHome} />
</Switch>
</BrowserRouter>
);
}
}
const Login = () => (
<div>
Login Content <NavLink to="/AppHome"> go to App</NavLink>
</div>
);
const Register = () => <div> Register Content </div>;
const AppHome = () => <div> Welcome to the App </div>;
class Authenticate extends React.Component {
render() {
return (
<>
<div>
<NavLink to={"/Login"}> Login </NavLink>
<NavLink to={"/Register"}> Register </NavLink>
</div>
</>
);
}
}
export default App;
Codesandbox
import React from 'react'
import ReactDOM from 'react-dom'
import {HashRouter, Route, Switch, NavLink} from 'react-router-dom'
class App extends React.Component {
render() {
return (
<HashRouter>
<Switch>
<Route path="/Login" component={Login} />
<Route path="/Register" component={Register} />
<Route path="/" component={AppHome} />
</Switch>
</HashRouter>
)
}
}
const Login = () => (
<div>
Login Content <NavLink to="/AppHome"> go to App</NavLink>
</div>
)
const Register = () => <div> Register Content </div>
const AppHome = () => <div> Welcome to the App </div>
export default App
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Can you please check this Codesandbox Once.

Routes are not responding with Back and forward browser button when using nested routes in reactjs

Hi guys I am a newbie to reactjs, I am trying to learn reactjs router. I have this weird thing happening to my Dashboard routes.
My App component have two routes "/login" and "/"
'/login' shows up the login screen and the '/' shows up the main dashboard screen.
In the dashboard I have sidenavigation component and Main content component.
I am trying to nest a set of Routes inside main component.
The routes are working fine when i navigate it through the links in the side navigation component. But when I try to click back or forward button in the browser it doesn't work. I am getting a blank screen without anything loaded.
please need your help guys.. any help will be highly appreciated.
Please find the code below.
//App.js
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import MainPage from "./Mainpage";
import LoginPage from "./components/pages/LoginPage";
import "./styleFiles/index.css";
class App extends Component {
render() {
return (
<div className="flexible-content">
<Route path="/" exact component={MainPage} />
<Route path="/login" component={LoginPage} />
</div>
);
}
}
export default App;
//MainPage.js
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import SideNavigation from "./components/sideNavigation";
import Footer from "./components/Footer";
import "./styleFiles/index.css";
import DashboardPage from "./components/pages/DashboardPage";
import ProfilePage from "./components/pages/ProfilePage";
import TablesPage from "./components/pages/TablesPage";
import InventoryPage from "./components/pages/InventoryPage";
class MainPage extends Component {
render() {
return (
<BrowserRouter>
<div className="flexible-content">
<SideNavigation />
<main id="content" className="p-5">
<Switch>
<Route path={"/"} exact component={DashboardPage} />
<Route path={"/Dashboard"} exact component={DashboardPage} />
<Route path="/profile" component={ProfilePage} />
<Route path="/tables" component={TablesPage} />
<Route path="/inventory" component={InventoryPage} />
<Route component={DashboardPage} />
</Switch>
</main>
<Footer />
</div>
</BrowserRouter>
);
}
}
export default MainPage;
//sideNavigation.js
import React from "react";
import logo from "../assets/logo_.svg";
import { MDBListGroup, MDBListGroupItem, MDBIcon } from "mdbreact";
import { NavLink } from "react-router-dom";
import "../styleFiles/sideBar.css";
const sideNavigation = () => {
return (
<div className="sidebar-fixed position-fixed">
<a href="#!" className="logo-wrapper waves-effect">
<img alt="MDB React Logo" className="img-fluid" src={logo} />
</a>
<MDBListGroup className="list-group-flush">
<NavLink exact={true} to="/" activeClassName="activeClass">
<MDBListGroupItem className="bgc">
<MDBIcon icon="chart-pie" className="mr-3" />
Testing Dashboard
</MDBListGroupItem>
</NavLink>
<NavLink to="/profile" activeClassName="activeClass">
<MDBListGroupItem className="bgc">
<MDBIcon icon="user" className="mr-3" />
Projects
</MDBListGroupItem>
</NavLink>
<NavLink to="/tables" activeClassName="activeClass">
<MDBListGroupItem className="bgc">
<MDBIcon icon="table" className="mr-3" />
Tables
</MDBListGroupItem>
</NavLink>
<NavLink to="/inventory" activeClassName="activeClass">
<MDBListGroupItem className="bgc">
<MDBIcon icon="fas fa-truck-loading" className="mr-3" />
Inventory
</MDBListGroupItem>
</NavLink>
<NavLink to="/404" activeClassName="activeClass" />
</MDBListGroup>
</div>
);
};
export default sideNavigation;
thanks in advance for your help guys...
When I made a small change to my code, I could eliminate that weird behavior.
the changes were only made to my App.js file.
please find the changes below
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import MainPage from "./Mainpage";
import LoginPage from "./components/pages/LoginPage";
import "./styleFiles/index.css";
class App extends Component {
render() {
return (
<div className="flexible-content ">
<Switch>
<Route path="/Main" exact component={MainPage} />
<Route path="/login" component={LoginPage} />
<Route component={MainPage} />
</Switch>
</div>
);
}
}
export default App;
I added a switch tag and a Generic Not Found route component to my app.js file.

React-Router nested routes loading blank page instead of loading inside parent component

I am new to React and trying to create a layout with nested routes. Here's my scenario
show Login when URL is /
show Dashboard when URL is /dashboard
show Profile when URL is /dashboard/profile (this should load
inside the dashboard content area)
The login page and dashboard page are loading properly when the URL is accessed in the browser but for /dashboard/profile, the browser goes to a blank page instead of loading it inside the dashboard component.
Index.js
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root'));
App.js
class App extends Component {
render() {
return (
<div>
{/* <Switch> */}
<Route exact path='/' component={SignIn}/>
<Route exact path='/dashboard' component={Dashboard}/>
{/* </Switch> */}
</div>
);
}
}
export default App;
Dashboard.js
class Dashboard extends React.Component {
render() {
const { classes } = this.props;
return (
<React.Fragment>
<CssBaseline />
<div className={classes.root}>
<Header classes={classes} open={this.state.open} click={this.handleDrawerOpen} />
<Sidebar classes={classes} open={this.state.open} click={this.handleDrawerClose} />
<main className={classes.content}>
<div className={classes.appBarSpacer} />
*********I expect profile component to load here
but when I access the URL /dashboard/profile I get a new blank page*********
Route path="/dashboard/profile" exact component={Profile} />
</main>
</div>
</React.Fragment>
);
}
}
You need to remove the exact prop from the Dashboard route (present in Switch) while doing the child routing.
This is the minimal implementation of your use case:
import React, { Component } from "react";
import "./styles.css";
import {
NavLink,
Redirect,
Route,
BrowserRouter as Router,
Switch
} from "react-router-dom";
const App = () => (
<Router>
<div className="App">
<ul>
<li>
<NavLink to="/login">Login</NavLink>
</li>
<li>
<NavLink to="/dashboard">Dashboard</NavLink>
</li>
</ul>
<Switch>
<Route exact path="/login" component={Login} />
<Route path="/dashboard" component={Dashboard} />
</Switch>
</div>
</Router>
);
const Login = () => <span>Login Page</span>;
const Dashboard = () => {
return (
<div>
<div>Dashboard Page</div>
<NavLink to="/dashboard/profile">Go to profile</NavLink>
<div>
<Route exact path="/dashboard/profile" component={Profile} />
</div>
</div>
);
};
const Profile = () => {
return <span>Profile Page</span>;
};
export default App;
You can find the working example here:https://codesandbox.io/s/z3py3672v3

Simple Conditional Routing in Reactjs

How to implement conditional routing i.e. if and only if some conditions satisfies, then routing should occur.
For example, if and only if the user enters the correct credentials, login should be successful and the user should be able to see the welcome page.
If we directly hit some URL like localhost:8080/welcome, that should not be navigated to welcome page. The welcome page should only be displayed after login.
How to achieve this, can anyone help me please?
App.js
import React, { Component } from 'react';
import Header from './Header';
class App extends Component{
render(){
return(
<div>
<Header />
</div>
);
}
}
export default App;
Header.js
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import Login from './Login';
import SignUp from './SignUp';
class Header extends Component{
render(){
return(
<div>
<nav class="navbar navbar-default">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li><Link to={Login}>Login</Link></li>
<li><Link to={Login}>SignUp</Link></li>
</ul>
</div>
</nav>
</div>
);
}
}
export default Header;
AllRoutes.js
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Login from './Login';
import SignUp from './SignUp';
import Welcome from './Welcome';
class AllRoutes extends Component{
render(){
return(
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/signup" component={SignUp} />
<Route exact path="/Welcome" component={Welcome} />
</Switch>
);
}
}
export default AllRoutes;
Welcome.js
import React, { Component } from 'react';
class Welcome extends Component{
render(){
return(
<div>
<h2>Welcome to MainPage..</h2>
</div>
);
}
}
export default Welcome;
To help answer your question, I think you may need to also ask how that route should get blocked. Looking through the example above, you don't yet have a mechanism that helps answer the question of "should I be able to visit this page". That might come from state, redux, or some other means of determining if the user is logged in.
Since react-router is just plain React (one of my favorite parts!!) you have all the tools available to you that you would to conditionally show any part of your React app.
Here are a couple examples of how you might achieve this (by no means is this exhaustive. Be creative! It all depends on your requirements and the tools you are using)
class AllRoutes extends Component{
render(){
return(
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/signup" component={SignUp} />
{ this.state.authenticated &&
<Route exact path="/Welcome" component={Welcome} />
}
</Switch>
);
}
}
One of my favorite ways to accomplish this is creating a ProtectedRoute component
class ProtectedRoute extends Component {
render() {
const { component: Component, ...props } = this.props
return (
<Route
{...props}
render={props => (
this.state.authenticated ?
<Component {...props} /> :
<Redirect to='/login' />
)}
/>
)
}
}
class AllRoutes extends Component {
render() {
return (
<Switch>
<Route path='/login' component={Login} />
<ProtectedRoute path='/welcome' component={Welcome} />
</Switch>
)
}
}
While I didn't include any specific logic to how state.authenticated was set, this may come from anywhere (by no means does it needs to come from state). Do your best to answer the question of "how do I determine whether a user is authenticated" and use that mechanism as the means to handle route authentication.
For that you need to break the entire app into two parts, normally accessible and protected part. Protected part will be accessible only after successful login.
To achieve that functionality, create a wrapper of protected part, and define its routes with path='/', and put the condition inside that. All the protected routes should be defined inside that wrapper component. If anyone try to access those routes without login, wrapper will redirect them to login page.
Like this:
class AllRoutes extends Component{
render(){
return(
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/signup" component={SignUp} />
<Route path="/" component={AppWrapper} />
</Switch>
);
}
}
AppWrapper Component (assuming you are using some way to maintain whether user is logged-in or not, so put the proper check in if condition):
import { Redirect } from 'react-router-dom'
class AppWrapper extends Component{
render(){
if(/*not login*/)
return <Redirect to="/login" />
return(
<div>
App wrapper
<Route path='/Welcome' component={Welcome} />
</div>
);
}
}
I would like to join the party with simple solution.
Just conditional render in the component prop in as follows:
<Router>
<Navigation />
<Switch>
<Route
exact
path="/"
component={
loading
? () => <div>Loading posts...</div>
: () => <Home posts={posts} />
}
/>
<Route path="/login" component={Login} />
</Switch>
</Router>
Here i am trying to fetch some data from an api when it fetched (loading) should be false and renders Home component.
You can do something like:
let redirectToUrl;
if ( not logged in ) //check condition
{
redirectToUrl = <Redirect to={loginPage}/>;
}
and use the same:
<Router>
<div>
{redirectToUrl}
<Switch>
<Route />
</switch>
</div>
</Router>
For the same you need to import from react-router-dom:
import {
BrowserRouter as Router,
Route,
browserHistory,
Redirect,
Link,
Switch
} from "react-router-dom";
Best way is to create a HOC.
Considering you are maintaining auth state in your redux store. Or else you can check with your own variable.
Create requireAuth.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
export default function(ComposedComponent) {
class Authentication extends Component {
static contextTypes = {
router: React.PropTypes.object
}
componentWillMount() {
if (!this.props.authenticated) {
this.context.router.push('/');
}
}
componentWillUpdate(nextProps) {
if (!nextProps.authenticated) {
this.context.router.push('/');
}
}
render() {
return <ComposedComponent {...this.props} />
}
}
function mapStateToProps(state) {
return { authenticated: state.auth.authenticated };
}
return connect(mapStateToProps)(Authentication);
}
Now in the routes you can use this hoc and pass the component.
import RequireAuth from './requireAuth';
...
<Route exact path="/Welcome" component={RequireAuth(Welcome)} />
The best and simple thing you can do is to create a state variable login and route based on the boolean values. the logic to set is up to you. i can show an example of simple routing based on condition. I store my pages in a array and use the map function to switch to different routes. For an example I have inserted my DesignerHome.js for your reference
This is my App.js
import React,{Component} from 'react';
import{BrowserRouter as Router,Switch,Route,Redirect,} from 'react-router-dom'
import MainHome from './MainHome'
import DesignerHome from './designer/DesignerHome'
export default class App extends Component{
constructor(){
super()
this.state={
login : true,
r_page :[
{
path :'/designerhome',
component : DesignerHome,
},]
}
}
render(){
return(
<Router>
<Switch >
<Route path='/' exact component={MainHome}/>
{this.state.r_page.map((item , i)=>(this.state.login?
<Route exact {...item}/> : <Redirect to="/" /> ))}
</Switch>
</Router>
)
}
}
This is my DesignerHome.js
import React,{Component} from 'react';
export default class DesignerHome extends Component{
render(){
return(
<div>
designer home
</div>
)
}
}
create a state for authentication. based on that navigate to the page.
Also I used render instead of component in Route.
import React, { Fragment, useState, useEffect } from "react";
import Dashboard from "./components/Dashboard";
import Login from "./components/Login";
import Register from "./components/Register";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const setAuth = (boolean) => {
setIsAuthenticated(boolean);
};
useEffect(() => {
isAuth(); // to be implemented
}, []);
return (
<Fragment>
<Router>
<div className="container">
<NavigationCard />
<Switch>
<Route
exact
path="/login"
render={(props) =>
!isAuthenticated ? (
<Login {...props} setAuth={setAuth} />
) : (
<Redirect to="/dashboard" />
)
}
/>
<Route
exact
path="/register"
render={(props) =>
!isAuthenticated ? (
<Register {...props} setAuth={setAuth} />
) : (
<Redirect to="/login" />
)
}
/>
<Route
exact
path="/dashboard"
render={(props) =>
isAuthenticated ? (
<Dashboard {...props} setAuth={setAuth} />
) : (
<Redirect to="/login" />
)
}
/>
</Switch>
</div>
</Router>
</Fragment>
);
}
export default App;

Resources