implementing the browser navigation in react application? - javascript

In browser , we do have back and forward button to navigate back and forth. If we are in the first page back will be disabled and in the last page forward is disabled. Am trying to implement the same in react application using react router.I can navigate to different pages on click of navigation menu But i need a help on implementing the browser navigation in the react application.
import React, {useEffect, useState } from "react";
import { Redirect, Switch, Route, withRouter } from "react-router";
import Page1 from "./Page1";
import Page2 from "./Page2";
import Page3 from "./Page3";
const App = (props) => {
return (
<React.Fragment>
<button>prev</button>
<button>next</button>
<Switch>
<Route exact path="/" render={() => <Redirect to="/page1" />} />
<Route path="/page1" component={Page1} />
<Route path="/page2" component={Page2} />
<Route path="/page3" component={Page3} />
</Switch>
</React.Fragment>
);
}
export default withRouter(App);
can u help me in implementing the browser navigation here?

The Solution to your problem, you can control using useHistory provided by react-router.
import React, { useEffect, useState } from "react";
import { Redirect, Switch, Route, withRouter, useHistory } from "react-router";
import Page1 from "./Page1";
import Page2 from "./Page2";
import Page3 from "./Page3";
const App = (props) => {
const history = useHistory();
return (
<React.Fragment>
<button onClick={() => history.goBack()}>Prev</button>
<button onClick={() => history.goForward()}>Next</button>
<Switch>
<Route exact path="/" render={() => <Redirect to="/page1" />} />
<Route path="/page1" component={Page1} />
<Route path="/page2" component={Page2} />
<Route path="/page3" component={Page3} />
</Switch>
</React.Fragment>
);
}
export default withRouter(App);

Related

Re-use navbar component with multiple components

I have a simple question. What is the best way to use a navbar with multiple components using react router? Just let me show the code so you can understand what I'm trying to say.
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Navbar>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Navbar>
</Switch>
</Router>
);
}
export default App;
So I have to reuse my Navbar component, and I tried to use <Navbar />, then the other routes below, but that wasn't working, and when I put <Navbar> </Navbar> that worked and the other components will appear, but is that the way I reuse my Navbar component?
Thanks for your time !!
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Route Component={Navbar}>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Route>
</Switch>
</Router>
);
}
export default App;
Try this!
If you want the Navbar to render only on certain routes then render it only on certain routes. Render the Navbar into a route outside the Switch and specify all the paths you want it to be rendered on in an array on the path prop.
Additional notes:
Within the Switch component, order and path specificity matter, reorder your routes to specify more specific paths before less specific paths. This allows you to not need to specify the exact prop for every route.
Don't specify both a component prop and render children on a single Route, see Route render methods. Just render the Redirect or Auth component as children.
Code:
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Route
path={["/profile", "/socialmedia"]}
component={Navbar}
/>
<Switch>
<Route path="/profile/:id" component={SingleUser} />
<Route path="socialmedia/photo/:id" component={SinglePhoto} />
<Route path="socialmedia/search" component={Search} />
<Route path="/socialmedia" component={SocialMedia} />
<Route path="/">
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
</Switch>
</Router>
);
}

Getting React Props after sending it from Route

I Am Sending React Component from a route as mention in this Link
<Route path='/StartCompaign' render={(props) => <CampaignStart {...props} isDashboard={true} /> } />
and i am getting props in another Component like
{props.childern.render.isDashboard ? <Header /> : "NO" }
APP.JSX file
import React from 'react';
import { Route, Switch } from 'react-router';
import Layout from './components/Layout';
import Home from './components/Dynamic/Home';
import Filter from './components/Dynamic/Filter';
import { AboutCampaign } from './components/Dynamic/AboutCampaign';
import { CampaignStart } from './components/Dynamic/CompaignStart';
import NotFound from './NotFound';
import {SignUp} from './components/Static/SignUp';
import { Login } from './components/Static/Login';
import Dashboard from './components/Dashboard'
import { withCookies } from 'react-cookie';
class App extends React.Component {
render() {
return (
<Switch>
<Layout>
<Route exact path='/' component={Home} />
<Route path='/filter' component={Filter}/>
<Route path='/Campaign/:campaignId' component={AboutCampaign}/>
<Route path='/SignUp' component={SignUp}/>
<Route path='/Login' component={Login}/>
<Route path='/Dashboard' render={(props) => <Dashboard {...props} isDashboard={true} /> } />
<Route path="" component={NotFound} />
</Layout>
</Switch>
);
}
}
export default withCookies(App);
Layout.JSX
import React from 'react';
import { Container } from 'reactstrap';
import Header from './Static/Header';
import Footer from './Static/Footer';
import TopNavigation from './Component/DashBoard/TopNavigation'
export default props => (
<div>
{props.isDashboard ? <Header /> : <TopNavigation /> }
<Container>
{props.children}
</Container>
<Footer />
</div>
);
I am trying to change the <Header/> and <TopNavigation /> in react application when the specfic route is called but props.isDashboard seemed undefined
It's because you are sending props to <Dashboard/> component
<Dashboard {...props} isDashboard={true} />
but not to <Layout /> component.
If Layout component needs to receive isDashboard props you need to pass it like
<Layout isDashboard={true} />
As Layout is parent component, if child components also needs the props you could always pass those to children easily.

Redirect from child route in react to parent if not authenticated

I am trying to redirect the user to the root url if they are not authenticated:
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './components/App';
import LoginPage from './components/login/LoginPage';
import DashboardPage from './components/dashboard/DashboardPage';
import { Redirect } from 'react-router-dom';
export default (
<Route path='/' component={App}>
<IndexRoute component={LoginPage} />
<Route
path='/dashboard'
render={props => (
isAuthenticated() ?
<DashboardPage {...props} /> :
<Redirect to='/' />
)}
/>
</Route>
);
I understand why this example doesn't work - App component is expecting 'children' props which are the nested components, but this is rendering them instead; what I don't understand is how to achieve a redirect if isAuthenticated returns false when trying to navigate to /dashboard - using component={...} doesn't work.

React Router Duplicate routes on Back Button

I have a react app. It is working fine. It uses redux,react-router 3. The routes work fine, but when I press the back button, they route gets duplicated. For example from localhost:3000/admin/main which I am currently, when I go back, it goes to localhost:3000/admin/admin/main, which return not found.
Here is my routes code:
export default (
<Route path="/" component={App}>
<Route path="home" component={requireNoAuthentication(HomeContainer)} />
<Route path="login" component={requireNoAuthentication(LoginView)} />
<Route exact path="admin/user" component={requireAuthentication(UserView)} />
<Route exact path="admin/main" component={requireAuthentication(UsersListView)} />
<Route path="secure" component={requireAuthentication(CustomerView)} />
<Route exact path="*" component={DetermineAuth(NotFound)} />
</Route>
);
I also get a console error: Adjacent JSX elements must be wrapped in an enclosing tag. If anyone can help it would be great thanks!!
Your HOC wrappers (requireNoAuthentication and requireAuthentication) and using exact (I think this might a react-router v4 only feature?) might be messing with your route history. Try restructuring your routes so that all of them fall under App -- some of the routes fall under RequireAuth, while the rest are public.
As a side note: you can avoid using React.cloneElement with passed down class methods and state by using Redux instead.
routes/index.js
import React from "react";
import { browserHistory, IndexRoute, Router, Route } from "react-router";
import App from "../components/App";
import Home from "../components/Home";
import Info from "../components/Info";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";
import Sponsors from "../components/Sponsors";
import RequireAuth from "../components/RequireAuth";
export default () => (
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route component={RequireAuth}>
<IndexRoute component={Home} />
<Route path="roster" component={ShowPlayerRoster} />
<Route path="roster/:id" component={ShowPlayerStats} />
<Route path="schedule" component={Schedule} />
</Route>
<Route path="info" component={Info} />
<Route path="sponsors" component={Sponsors} />
</Route>
</Router>
);
index.js
import React from "react";
import { render } from "react-dom";
import App from "../routes";
import "uikit/dist/css/uikit.min.css";
render(<App />, document.getElementById("root"));
components/App.js
import React, { Component, Fragment } from "react";
import { browserHistory } from "react-router";
import Header from "./Header";
export default class App extends Component {
state = {
isAuthenticated: false
};
isAuthed = () => this.setState({ isAuthenticated: true });
unAuth = () =>
this.setState({ isAuthenticated: false }, () => browserHistory.push("/"));
render = () => (
<Fragment>
<Header
isAuthenticated={this.state.isAuthenticated}
unAuth={this.unAuth}
/>
{React.cloneElement(this.props.children, {
isAuthenticated: this.state.isAuthenticated,
isAuthed: this.isAuthed
})}
</Fragment>
);
}
components/RequireAuth.js
import React, { Fragment } from "react";
import Login from "./Login";
export default ({ children, isAuthenticated, isAuthed }) =>
!isAuthenticated ? (
<Login isAuthed={isAuthed} />
) : (
<Fragment>{children}</Fragment>
);

Why cant I separate <Switch> to a different module?

Goal
I'm trying to extract the <Switch> with its <Route>'s out to a different module.
Problem
The url is being changed to the new path, but the content doesn't (only when I refresh it changes).
I'm trying to understand what am I missing.
EDITED:
live example: https://stackblitz.com/edit/separated-switch-module
working example:
<BrowserRouter>
<div>
<Link to="/"> Home </Link>
<Link to="contacts"> Contacts </Link>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/contacts" component={Contacts} />
</Switch>
</div>
</BrowserRouter>
failing exmaple:
<BrowserRouter>
<div>
<Link to="/"> Home </Link>
<Link to="contacts"> Contacts </Link>
<SwitchedRoutes/>
</div>
</BrowserRouter>
EDITED:
SwitchedRoutes:
import React from "react";
import { observer, inject } from "mobx-react";
import { Switch, Route } from "react-router-dom";
#inject('pageStore')
#observer
export default class extends React.Component {
render(){
const {
home,
contacts
} = this.props.pageStore.pages;
return (
<Switch>
<Route exact path={home.path} render={()=> <Home />} />
<Route path={contacts.path} render={()=> <Contacts/>} />
</Switch>
)
}
}
Since react-router v4 changed an API a bit you need to give to the all underlying components such as Switch, Link and etc a router context. (Something like subscriber to the routing stuff), as soon as you disconnects the module to the separate file it loses the context.
just add this to the SwitchedRoutes.js
import React from 'react';
import { withRouter } from 'react-router'
import {Switch, Route} from 'react-router-dom';
import {inject, observer} from 'mobx-react';
const Home = () => <h1>Home</h1>;
const Contacts = () => <h1>Contents</h1>;
const switchedRouter = inject('store')(observer(props => {
const {home, contacts} = props.store.routes;
return(
<Switch>
<Route exact path={home.path} component={Home}/>
<Route path={contacts.path} component={Contacts}/>
</Switch>
);
}));
export default withRouter(switchedRouter)
we simply wrapped the component with withRouter HoC which provides us a correct react-router context.
https://separated-switch-module-j92psu.stackblitz.io

Categories