1

Following issue: I am trying to create an authentication system in react, which let's a user login, sign up and reset the password. The problem is, I want to let the user go certain routes such as /profile, but display the content if he is logged in. If he is not logged in, I want to simply display the navigation bar and a small login component.

So far I tried something like this: (In order to make it more readable I left out the action-blocks)

const Profile = ({ history }) => {
  const [values, setValues] = useState({
    username: "",
    email: "",
    password: ""
  });

  const [isShowingAuth, setIsShowingAuth] = useState(null);

  const { username, email, password } = values;


  useEffect(() => {

    if (!isLoggedIn()) {
      setIsShowingAuth("login");
    } else {
      loadProfileData();
    }
  }, []);

  const loadProfileData = () => {
    const userEmail = isLoggedIn().email;
    const token = getCookie("token");

    axios({
      method: "GET",
      url: `${process.env.REACT_APP_BACKEND_URL}/user`,
      headers: { Authorization: `Bearer ${token}` },
      data: { userEmail }
    })
      .then(response => {
        // Do something
      })
      .catch(error => {
        // Do something
      });
  };

  const handleChange = name => event => {
    setValues({ ...values, [name]: event.target.value });
  };

  const handleUpdateUserSubmit = e => {
    e.preventDefault();

    const token = getCookie("token");

    axios({
      method: "PUT",
      url: `${process.env.REACT_APP_BACKEND_URL}/user/update`,
      headers: { Authorization: `Bearer ${token}` },
      data: { username, password, email }
    })
      .then(response => {
        // Do something 
      })
      .catch(error => {
        // Do something
        }

        store.addNotification({
          ...defaultSettings,
          type: "danger",
          title: "User update error",
          message: error.response.data.errorMsg
        });
      });
  };


  const deleteAccount = () => {
    const token = getCookie("token");

    axios({
      method: "DELETE",
      url: `${process.env.REACT_APP_BACKEND_URL}/user`,
      headers: { Authorization: `Bearer ${token}` }
    })
      .then(response => {
        // Do something
      })
      .catch(error => {
        // Do something
  };

  const showDeleteConfirmation = () => {
      // Do something
  };

  return (
    <Layout isShowingAuth={isShowingAuth}>
      {isLoggedIn() && isLoggedIn().role === "member" ? (
        <>
          <ReactNotifications />
          <h1 className='mt-5 pl-3'>Profile</h1>
          <form className='form col-md-6 mt-3'>
            <div className='form-group'>
              <label>Name</label>
              <input
                type='text'
                className='form-control'
                value={username}
                onChange={handleChange("username")}
              />
            </div>
            <div className='form-group'>
              <label>Email</label>
              <input
                type='email'
                className='form-control'
                value={email}
                onChange={handleChange("email")}
                disabled
              />
            </div>
            <div className='form-group'>
              <label>Password</label>
              <input
                type='password'
                className='form-control'
                value={password}
                onChange={handleChange("password")}
                placeholder='Enter your new password'
                autoComplete='on'
              />
            </div>
            <button type='submit' className='btn btn-outline-primary' onClick={handleUpdateUserSubmit}>
              Update User
            </button>
            <button type='button' className='btn btn-outline-danger ml-3' onClick={showDeleteConfirmation}>
              Delete account
            </button>
            <button type='button' className='btn btn-outline-danger ml-3 mt-2 mt-md-0'>
              Want to change your email?
            </button>
          </form>
          {showAlert}
        </>
      ) : null}
    </Layout>
  );
};

Basically I am checking through the isLoggedIn() method if the user is logged in. If he is, I want to render the content, if not I am returning only the layout. The layout contains the navigation bar.

The problem now is, that once the user logs in while being on the route /profile, the component doesn't remount, which means the useEffect(()=> {},[]) is not called again and my profile data is not loaded.

I already tried to refresh the page once logged in through history.push(history.location.pathname), but this doesn't trigger a remount either.

I'm no wondering how to properly trigger a remount after login, and if the way I am setting my authentication system up is secure or if there are better solutions.

Any help / feedback appreciated thanks :)

aron fischer
  • 91
  • 1
  • 9
  • 1
    Try `document.location = history.location.pathname;` – huytc Mar 26 '20 at 08:32
  • simple fast end straight forward. Thank you very much it worked. – aron fischer Mar 26 '20 at 08:35
  • Could you maybe also give me feedback if the way I'm trying to set things up is a good / secure way to do so? – aron fischer Mar 26 '20 at 08:36
  • I would normally implement it like in this example: https://reacttraining.com/react-router/web/example/auth-workflow. The idea is basically the same as yours, but offers better reusability. Create a special component "PrivateRoute" to protect private routes, then reuse that component for whatever routes you need to protect, instead of having to duplicate that login check in each page. – huytc Mar 26 '20 at 08:42
  • But if you only need this check for one page then I think it's good enough. – huytc Mar 26 '20 at 08:43
  • Yes the problem with this is, that I have a sign up component popping up, my sign up / login component does have it's own route, so I can't redirect a user there. Is there a more reusable way for this implementation ? – aron fischer Mar 26 '20 at 09:02
  • Well instead of returning a Login route, I think you can just call your code to show the login component. `if (loggedIn()) return ; else { showLogin(); return null; }` – huytc Mar 26 '20 at 09:12

0 Answers0