user6488504
user6488504

Reputation:

react: React-router Link not loading a component

I have a login page which has a forgot password link and it takes the user to forgot password page.

When I click on the forgot password link, it changes the URL but does not load the component.

Code for login page

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";

// assets
import Logo from "../../../assets/images/kvh-logo.svg";
import bgImgArray from "../../../assets/images/bg";

import { Button, Form, Input, InputGroup, InputGroupAddon } from "reactstrap";

import "./Login.css";

const Login = (props) => {
  const [loading, setLoading] = useState(false);
  const userid = useFormInput("");
  const password = useFormInput("");
  const [error, setError] = useState(null);

  // for changing backgrounds
  const [index, setIndex] = useState(0);

  return (
    <div className="container-fluid backgroundContainer">
      <div className="Login">
        <div className="login-form-container">
          <div className="logo">
            <img src={Logo} className="App-logo" alt="logo" />
          </div>
          <div className="content">
            <Form className="login-form">
              <InputGroup>
                <InputGroupAddon
                  className="input-group-addon"
                  addonType="prepend"
                >
                  <i className="fa fa-user"></i>
                </InputGroupAddon>
                <Input
                  autoFocus
                  type="email"
                  aria-label="Username"
                  aria-describedby="username"
                  aria-invalid="false"
                  placeholder="Username or Email"
                  {...userid}
                />
              </InputGroup>
              <InputGroup>
                <InputGroupAddon
                  className="input-group-addon"
                  addonType="prepend"
                >
                  <i className="fa fa-lock"></i>
                </InputGroupAddon>
                <Input
                  type="password"
                  placeholder="Password"
                  aria-label="password"
                  aria-describedby="password"
                  {...password}
                />
              </InputGroup>
              <div className="form-actions">
                {error && (
                  <>
                    <small style={{ color: "red" }}>{error}</small>
                    <br />
                  </>
                )}
                <br />
                <Button
                  className="pull-right"
                  block="true"
                  type="submit"
                  bssize="small"
                  value={loading ? "Loading..." : "Login"}
                  onClick={handleLogin}
                  disabled={loading}
                >
                  Login
                </Button>
                <br />
              </div>
              <div className="forgotPassword">
                <Link to="/forgotPassword">Forgot password?</Link>
              </div>
            </Form>
          </div>
        </div>
      </div>
    </div>
  );
};

const useFormInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);

  const handleChange = (e) => {
    setValue(e.target.value);
  };
  return {
    value,
    onChange: handleChange,
  };
};

export default Login;

In routing code, I have Admin Layout which looks after the dashboard and AuthLayout which looks after the Login page.

I tried searching for the solution but unfortunately couldn't find any solutions. Hence, posting it here.

Router Code

import React from "react";
import {
  BrowserRouter as Router,
  Route,
  Switch,
  Redirect,
} from "react-router-dom";

import { createBrowserHistory } from "history";

import AdminLayout from "layouts/Admin/Admin.js";
import AuthLayout from "layouts/Auth/Auth.js";
import ResetPassword from "../components/pages/reset-password/ResetPassword";

const hist = createBrowserHistory();

const AppRouter = () => {
  return (
    <Router history={hist}>
      <Switch>
        <Route path="/admin" render={(props) => <AdminLayout {...props} />} />
        <Route path="/" render={(props) => <AuthLayout {...props} />} />
        <Route path="/forgotPassword" component={ResetPassword} />
        <Redirect from="/" to="/auth" />
      </Switch>
    </Router>
  );
};

export default AppRouter;

Adding Auth Layout Code

import React from "react";
import { Route, Switch, Redirect, Link } from "react-router-dom";

import Login from "../../components/pages/login/Login";
import ResetPassword from "../../components/pages/reset-password/ResetPassword";


import routes from "routes/routes.js";

class Pages extends React.Component {
  getRoutes = (routes) => {
    return routes.map((prop, key) => {
      if (prop.collapse) {
        return this.getRoutes(prop.views);
      }
      if (prop.layout === "/auth") {
        return (
          <Route
            path={prop.layout + prop.path}
            component={prop.component}
            key={key}
          />
        );
      } else {
        return null;
      }
    });
  };
  getActiveRoute = (routes) => {
    let activeRoute = "WATCH";
    for (let i = 0; i < routes.length; i++) {
      if (routes[i].collapse) {
        let collapseActiveRoute = this.getActiveRoute(routes[i].views);
        if (collapseActiveRoute !== activeRoute) {
          return collapseActiveRoute;
        }
      } else {
        if (
          window.location.pathname.indexOf(
            routes[i].layout + routes[i].path
          ) !== -1
        ) {
          return routes[i].name;
        }
      }
    }
    return activeRoute;
  };

  componentDidMount() {
    document.documentElement.classList.remove("nav-open");
  }
  render() {
    return (
      <div className="wrapper wrapper-full-page" ref="fullPages">
        <div className="full-page">
          <Login {...this.props}></Login>
          <div className="forgotPassword">
            <Link to="/forgotPassword">Forgot password?</Link>
          </div>
          <Switch>
            {this.getRoutes(routes)}
            <Redirect from="*" to="/auth/login" />
          </Switch>
        </div>
      </div>
    );
  }
}

export default Pages;

Upvotes: 1

Views: 1135

Answers (5)

Drew Reese
Drew Reese

Reputation: 202836

The issue is in the way you've specified the order of the routes. The Switch component "Renders the first child <Route> or <Redirect> that matches the location. The path "/" rendering the AuthLayout component will be matched by any URL path, the "/forgotPassword" route is unreachable.

Within the Switch component you should order the routes in inverse order of path specificity. In other words, the more specific paths should be rendered prior to less specific paths. The idea is that if any given path doesn't match the URL path it "falls-through" to the less and less specific route paths until eventually it hits either a "/" or generic "catch-all" route.

There's an additional issue you'll hit after reordering the routes with the "/" route which will block the "catch-all" Redirect. For this one route you'll need to use the exact prop so only exactly "/" will match, and then any other path that wasn't already matched above will be safely handled by the redirect. Of course, for this redirect to work you actually need to render a route for path="/auth" somewhere. Below I've simply mapped it also to the AuthLayout route component.

Example suggestion:

<Switch>
  <Route path="/admin" component={AdminLayout} />
  <Route path="/forgotPassword" component={ResetPassword} />
  <Route path={["/auth", "/"]} component={AuthLayout} />
  <Redirect to="/auth" />
</Switch>

Upvotes: 0

Ayush Sharma
Ayush Sharma

Reputation: 99

Recently I faced this issue with React 18. Version of react was 18.0.1 and react-router-dom was 5.1.0 so StrictMode is causing the issue Just remove or comment the Tag <React.StrictMode> and it should work fine.

Upvotes: 0

Hamid Sarani
Hamid Sarani

Reputation: 795

look at this code that you wrote:

<Route path="/" render={(props) => <AuthLayout {...props} />} />
<Route path="/forgotPassword" component={ResetPassword} />

it's never going to /forgotPassword because path always match with first Route. you should use exact props:

<Route exact path="/" render={(props) => <AuthLayout {...props} />} />
<Route exact path="/forgotPassword" component={ResetPassword} />

Upvotes: 0

Anil Kumar
Anil Kumar

Reputation: 2309

Wrap inside Router as given below.

import {
 BrowserRouter as Router,
} from "react-router-dom";

<Router><Link to="/forgotPassword">Forgot password?</Link> <Router/>

Upvotes: 0

devserkan
devserkan

Reputation: 17608

If you create your own history then you should use Router instead of BrowserRouter.

import {
  Router,
  Route,
  Switch,
  Redirect,
} from "react-router-dom";

Because, BrowserRouter comes with its own history and you provide another one, this causes the problem.

Upvotes: 0

Related Questions