React Router Redirect path issue

Hi, folks. I’m running into an issue with React Router’s Redirect component, and I was wondering if I could get another pair of eyes on it to find out what’s going wrong. It always redirects to '/' instead of the path that I have in the to object. Here’s the code. The Redirect is in the conditional return statements at the bottom.

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

function Private(props) {
  let [user, updateUser] = useState({});
  let [loggedOut, setLoggedOut] = useState(false);

  useEffect(() => {
    getUser();
  }, []);

  let flashSuccess;
  try {
    flashSuccess = props.location.state.flashSuccess;
  } catch {}

  const getUser = () => {
    fetch("/api/getUserInfo")
      .then(res => res.json())
      .then(json => {
        updateUser(json);
      });
  };

  const logout = () => {
    fetch("/api/logout").then(() => {
      window.localStorage.removeItem("qrs");
      setLoggedOut(true);
    });
  };

  // REDIRECT HERE ************************************************
  if (loggedOut) {
    return (
      <Redirect
        to={{
          path: "/login",
          state: { flashInfo: "Please log in to continue." }
        }}
      />
    );
  } else {
    return (
      <div className="App">
        {flashSuccess ? (
          <div className="alert alert-success">{flashSuccess}</div>
        ) : null}
        <h1>IT WORKS!!!</h1>
        <h1>{JSON.stringify(user)}</h1>
        <button className="btn btn-primary" onClick={logout}>
          Log Out
        </button>
      </div>
    );
  }
}

export default Private;

I’m using the exact same technique in another component, and it works just fine there. That code, for comparison:

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

function Login(props) {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [redirect, setRedirect] = useState({
    redirect: false,
    path: "",
    msg: ""
  });
  const [flashError, setFlashError] = useState("");

  let flashSuccess;
  try {
    flashSuccess = props.location.state.flashSuccess;
  } catch {}

  let flashInfo;
  try {
    flashInfo = props.location.state.flashInfo;
  } catch {}

  const handleSubmit = async e => {
    e.preventDefault();
    let options = {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: username, password: password })
    };
    fetch("/api/login", options)
      .then(response => response.json())
      .then(json => {
        setUsername("");
        setPassword("");
        if (json.error) {
          props.location.state.flashSuccess = "";
          setFlashError(json.error);
        } else if (json.user) {
          window.localStorage.setItem("qrs", json.user);
          setRedirect({
            redirect: true,
            path: "/private",
            msg: "Login successful!"
          });
        }
      });
  };

  // REDIRECT HERE *********************************************
  if (redirect.redirect) {
    return (
      <Redirect
        to={{
          pathname: redirect.path,
          state: { flashSuccess: redirect.msg }
        }}
      />
    );
  } else {
    return (
      <div>
        <h1>Login</h1>
        {flashSuccess ? (
          <div className="alert alert-success">{flashSuccess}</div>
        ) : flashError ? (
          <div className="alert alert-danger">{flashError}</div>
        ) : flashInfo ? (
          <div className="alert alert-info">{flashInfo}</div>
        ) : null}
        <form onSubmit={handleSubmit}>
          <div className="form-group">
            <label htmlFor="exampleInputEmail1">Username</label>
            <input
              type="username"
              className="form-control"
              id="exampleInputEmail1"
              onChange={e => setUsername(e.target.value)}
              value={username}
              autoFocus
            />
          </div>
          <div className="form-group">
            <label htmlFor="exampleInputPassword1">Password</label>
            <input
              type="password"
              className="form-control"
              id="exampleInputPassword1"
              onChange={e => setPassword(e.target.value)}
              value={password}
            />
          </div>
          <button type="submit" className="btn btn-primary">
            Submit
          </button>
        </form>
      </div>
    );
  }
}

export default Login;

Again, it’s in the conditional return statements at the bottom.
Thanks for taking a look!

Hi. If you want <Redirect /> to work the way you expect, you should place it inside of your component’s render method so that it should eventually be considered as a DOM element, otherwise it won’t work. Cheers. Julian

How would this work with functional components with hooks, since they don’t have a render method?

Aaaaand it turns out it was because I was using “path” instead of “pathname”…

1 Like