React-router: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 263: Line 263:
export default authService;
export default authService;
</syntaxhighlight>
</syntaxhighlight>
==Create Route==
==Create Private Route==
We create this function which checks if the user is authenticated and either renders the Component passed in or redirects to the login page.
We create this function which checks if the user is authenticated and either renders the Component passed in or redirects to the login page.
<syntaxhighlight lang="JavaScript">
<syntaxhighlight lang="JavaScript">
Line 283: Line 283:


export default PrivateRoute;
export default PrivateRoute;
</syntaxhighlight>
==Change Routes to Use Private Route==
Now we put the private where appropriate
<syntaxhighlight lang="JavaScript">
  <Router>
      <PrivateRoute path="/" component={Home} exact />
      <PrivateRoute path="/explore" component={Explore} />
      <Privateoute path="/messages" component={Messages} />
      <PrivateRoute path="/profile" component={Profile} />
      <Route path="/auth/login" component={Login} />
      <Route path="/auth/Register" component={Register} />
      <Route path="/auth/logout" component={Logout} />
      <Route component={PageNotFound} />
    </Switch>
  </Router>
</syntaxhighlight>
</syntaxhighlight>



Revision as of 11:48, 6 July 2021

Introduction

This page is about routering with React.

Setup

Install package for Router

npm i react-router-dom

Add BrowserRouter to Index.js

...
import { BrowserRouter } from 'react-router-dom';
...
ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

Add Routes to App.js

We need to a routes to the the router we support.

import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';

import Explore from './components/Explore';
import Home from './components/Home';
import Messages from './components/Messages';
import Profile from './components/Profile';

function App() {
  return (

    <Router>
        <div>
          <h2>Welcome to React Router Tutorial</h2>
          <nav className="navbar navbar-expand-lg navbar-light bg-light">
          <ul className="navbar-nav mr-auto">
            <li><Link to={'/'} className="nav-link"> Home </Link></li>
            <li><Link to={'/explore'} className="nav-link">Explore</Link></li>
            <li><Link to={'/messages'} className="nav-link">Messages</Link></li>
            <li><Link to={'/profile'} className="nav-link">Profile</Link></li>
          </ul>
          </nav>
          <hr />
          <Switch>
              <Route exact path='/' component={Home} />
              <Route path='/explore' component={Explore} />
              <Route path='/messages' component={Messages} />
              <Route path='/profile' component={Profile} />
          </Switch>
        </div>
      </Router>

  );
}

export default App;

Create Pages

Functional Based

Create a component for each page

import React from 'react'

const Home = () => {
  return (
    <div>
        <h2>Home</h2>
    </div>
  );
};
export default Home

Class Component Based

Create a component for each page

import React, { Component } from 'react';

class Profile extends Component {
  render() {
    return (
        <div>
          <h2>Profile</h2>
        </div>
    );
  }
}
export default Profile;

Component Based

NavLink Component

This allows us to work with the activeClassName and exact to highlight the list which is active.

  <Router>
    <Nav authenticated={!defaultToSignIn} />
    <hr />
    <Switch>
      <Route path="/" component={Home} exact />
      <Route path="/auth/login" component={Login} />
      <Route path="/auth/Register" component={Register} />
      <Route path="/auth/logout" component={Logout} />
    </Switch>
  </Router>

And for some of the NavLink routes

            <li className="nav-item">
              <NavLink
                to="/home"
                aria-current="page"
                className="nav-link"
                exact
              >
                Home
              </NavLink>
            </li>
        </ul>
        <ul className="navbar-nav ms-auto mb-2 mb-lg-0">
            <li className="nav-item">
              <NavLink to="/explore" aria-current="page" className="nav-link">
                Explore
              </NavLink>
            </li>
            <li className="nav-item">
              <NavLink to="/messages" aria-current="page" className="nav-link">
                Messages
              </NavLink>
            </li>

Prompt Component

We can prevent leaving of a page with the Prompt component. For example.

...
  return (
    <div className="Login">
      {error && <p intent="danger">{error}</p>}
      <Prompt
        when={!usernameValid || !passwordValid}
        message="Leaving page will loose your data"
      />
      <Form onSubmit={handleSubmit} className="row g-3 needs-validation">
        <div>
          <div className="col-md-4">
            <Form.Group size="lg" controlId="username">
              <Form.Label>Username</Form.Label>
              <Form.Control
...

Adding a 404 Page

To implement this we just create a route with no path and a component

  <Router>
    <Nav authenticated={!defaultToSignIn} />
    <hr />
    <Switch>
      <Route
        exact
        path="/"
        render={() =>
          defaultToSignIn ? (
            <Redirect to="/auth/login" />
          ) : (
            <Redirect to="/home" />
          )
        }
      />
      <ProtectedRoute path="/" component={Home} exact />
      <ProtectedRoute path="/explore" component={Explore} />
      <ProtectedRoute path="/messages" component={Messages} />
      <ProtectedRoute path="/profile" component={Profile} />
      <Route path="/auth/login" component={Login} />
      <Route path="/auth/Register" component={Register} />
      <Route path="/auth/logout" component={Logout} />
      <Route component={PageNotFound} />
    </Switch>
  </Router>

Rendering Component with Parameters

When you need to add props to the component to render we use the render property which takes a function as an argument and should return the Component for the page.

Router

  <Router>
    <Switch>
      <Route path="/auth/logout" component={Logout} />
      <Route path="/compwithprops" render={() => {
           return <CompWithProps prop1="#ff0000" prop2='Red'/>
      }) />
      <Route component={PageNotFound} />
    </Switch>

Component

For the component we need to wrap it with withRouter in a HOC.

import React from "react";

const CompWithProps = ({prop1,prop2}) => (
  <div>
..
  </div>
);

CompWithProps.proptypes = {
    prop1: PropTypes.string.isRequired,
    prop2: PropTypes.string.isRequired,
}

export default withRouter(CompWithProps);

Custom Route with Parameters

Here we create a custom route which takes a parameter :eid

...
<CustomRoute path={'/api/orders/:eid'} component={Home} />
...

I the custom route we now Here we can create a Route which pulls this data in the props. Like the example above we can render the component Home and the eid will be available in the props.match.params.eid

import React from "react";
import { Route } from "react-router-dom";

const CustomRoute = ({ component: ComponentToRender, ...rest }) => (
  <Route
    {...rest}
    render={(props) => {
      alert(`Cusom Route ${props.match.params.eid} `);
      return <ComponentToRender {...props} />;
    }}
  />
);
export default CustomRoute;

Protected Route

Authentication Service

We create an authService which emulates the following

import Cookies from "universal-cookies";

const cookies = new Cookies();
const authService = {
  isAuthenticated() {
    return cookies.get("auth") === "true";
  },

  signIn(cb) {
    cookies.set("auth", true, { path: "/" });
    setTimeout(cb, 100);
  },

  signOut(cb) {
    cookies.set("auth", false, { path: "/" });
    setTimeout(cb, 100);
  },
};

export default authService;

Create Private Route

We create this function which checks if the user is authenticated and either renders the Component passed in or redirects to the login page.

import React from "react";
import { Redirect } from "react-router-dom";
import authService from "../service/authService";

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest}
    render={(props) => {
      authService.isAuthenticated() ? (
        <Component {...props} />
      ) : (
        <Redirect to="/login" />
      );
    }}
  />
);

export default PrivateRoute;

Change Routes to Use Private Route

Now we put the private where appropriate

  <Router>
      <PrivateRoute path="/" component={Home} exact />
      <PrivateRoute path="/explore" component={Explore} />
      <Privateoute path="/messages" component={Messages} />
      <PrivateRoute path="/profile" component={Profile} />
      <Route path="/auth/login" component={Login} />
      <Route path="/auth/Register" component={Register} />
      <Route path="/auth/logout" component={Logout} />
      <Route component={PageNotFound} />
    </Switch>
  </Router>

Router Children Component

All router children components get the following props.

  • match Exact Match, Params, Path and matching Url
  • location Key, path name and search
  • history This is the browser history

Transitions

You need to provide a class prefix in this case trans.

import {TransitionGroup, CSSTransition} from 'react-transition-group'

<TransactionGroup>
  <CSSTransition key={location.key} classNames={'trans'} timeout={1000}>
    <Switch location={location}>
     <Route path={`${match.url}`} component={LoremNumber} exact/>
     <Route path={`${match.url}/:id`} component={LoremNumber} exact/>
    </Switch>
</TransactionGroup>

And the CSS

.trans-enter {
   opacity: 0;
   z-index: 1;
}

.trans-exit {
   display: none
}

.trans-enter.trans-enter-active {
   opacity: 1;
   transition: opacity 1000ms ease-in;
}