React Router TypeError: Cannot read property 'state' of undefined

Viewed 475

I am making a basic routing app in react and redux and i am getting an error when i want to redirect to the referrer. Error happens in the line:


    this.referrer =  props.location.state.referrer || "/";

This is my Login component.

import React, { Component, createRef } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import axios from "axios";

import { updateAuthTokens, updateLoggedin } from "./redux/actions/actions";

class Login extends Component {
  constructor(props) {
    super(props);
    this.idRef = createRef();
    this.pwdRef = createRef();
    this.state = {
      isLoggedIn: false,
      isError: false,
      identifier: "",
      password: "",
    };
    this.postLogin = this.postLogin.bind(this);
    this.referrer =  props.location.state.referrer || "/";
  }

  postLogin(e) {
    e.preventDefault();
    const identifier = this.idRef.current.value;
    const password = this.pwdRef.current.value;
    axios
      .post(process.env.REACT_APP_BASE_URL + "/auth/local", {
        identifier,
        password,
      })
      .then((result) => {
        if (result.status === 200) {
          this.props.ul(true);
          this.props.uat(result.jwt);
          this.setState({ isLoggedIn: true });
        } else {
          this.setState({ isError: true });
        }
      })
      .catch((e) => {
        this.setState({ isError: true });
      });
  }

  render() {
    if (this.state.isLoggedIn) {
      return <Redirect to={this.referrer} />;
    } else {
      return (
        <div>
          <form>
            <input type="username" ref={this.idRef} placeholder="email" />
            <input type="password" ref={this.pwdRef} placeholder="password" />
            <button onClick={this.postLogin}>Sign In</button>
          </form>
          {this.state.isError && (
            <p>The username or password provided were incorrect!</p>
          )}
        </div>
      );
    }
  }
}
const mapStateToProps = (state) => {
  return {
    isLoggedIn: state.isLoggedIn,
  };
};
const mapDispatchToProps = {
  ul: updateLoggedin,
  uat: updateAuthTokens,
};
export default connect(mapStateToProps, mapDispatchToProps)(Login);

Redirect happens from this component:

import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";

class PrivateRoute extends React.Component {
  render() {
    const { isLoggedIn, children, ...rest } = this.props;
    if (isLoggedIn) {
      return <Route {...rest}>{children}</Route>;
    } else {
      return (
        <Redirect
          to={{
            pathname: "/login",
            state: { referrer: this.props.location }
          }}
        />
      );
    }
  }
}
const mapStateToProps = (state) => {
  return {
    isLoggedIn: state.isLoggedIn,
  };
};
export default connect(mapStateToProps, null)(PrivateRoute);

And my routes are here:

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

import { connect } from "react-redux";

import Home from "./Home";
import Admin from "./Admin";
import Members from "./Members";

import Login from "./Login";
import PrivateRoute from "./PrivateRoute";

import "./App.css";

class App extends Component {
  render() {
    return (
      <Router><div>
        <ul>
          <li>
            <Link to="/">Home Page</Link>
          </li>
          <li>
            <Link to="/members">Members</Link>
          </li>
          <li>
            <Link to="/admin">Admin</Link>
          </li>
        </ul>
      </div>
        <Switch>
          <Route path="/login">
            <Login />
          </Route>
          <Route exact path="/">
            <Home />
          </Route>
          <PrivateRoute path="/members">
            <Members />
          </PrivateRoute>
          <PrivateRoute path="/admin">
            <Admin />
          </PrivateRoute>
        </Switch>
      </Router>
    );
  }
}
const mapStateToProps = (state) => {
  return {
    isLoggedIn: state.isLoggedIn,
  };
};
export default connect(mapStateToProps, null)(App);

I haven't been able to get it to work and have had to comment it out which means i always end up in the home page instead of my intended location.

Any help/insight would be appreciated.

1 Answers

for accessing location as props change:

       <Route path="/login">
            <Login />
       </Route>
       <Route exact path="/">
            <Home />
       </Route>
       <PrivateRoute path="/members">
            <Members />
       </PrivateRoute>
       <PrivateRoute path="/admin">
            <Admin />
       </PrivateRoute>

to

       <Route path="/login" component={Login} />
       <Route exact path="/" component={Home} />
       <PrivateRoute path="/members" component={Members} />
       <PrivateRoute path="/admin" component={Admin} />

You are not going to always redirect so change:

    this.referrer =  props.location.state.referrer || "/";

to

    this.referrer = props.location.state ? props.location.state.referrer : "/";
Related