2

When I use the new navigate function in ReactJS React Router DOM it makes the page unresponsive. I think there is an error in my code because when I add the navigate react-router-dom function to a button like () => navigate('home') it works. But, when I add it in useEffect it doesn't work, the page becomes unresponsive.

Please check my code if there are any errors because I do not know a lot about this.

import React, { useEffect, useState } from 'react';

import './App.css';

import {
  BrowserRouter as Router,
  Routes,
  Route,
  Link,
  Navigate,
  useNavigate
} from "react-router-dom";
import Home from './Pages/Home';
import Login from './Pages/Login';

import {
  getAuth,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  onAuthStateChanged
} from "firebase/auth";

import {auth} from './Config';


function App() {

  const [authenticated, setAuthenticated] = useState(false);

  const navigate = useNavigate();

  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        setAuthenticated(true);
        navigate('home') // doesn't work
      } else {
        setAuthenticated(false);
      }
    })
  })

  const signup = (email, pass) => {
    createUserWithEmailAndPassword(auth, email, pass)
      .then((userCredential) => {
        const user = userCredential.user;
        console.log(user)
        navigate('home')
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        console.log(errorMessage)
      });
  }

  const login = (email, pass) => {
    signInWithEmailAndPassword(auth, email, pass)
      .then((credentials) => {
        console.log(credentials.user);
      })
      .catch((error) => {
        console.log(error.message);
      })
  }

  return (
    <Routes>
      <Route path='/' element={<button className="primary-button" onClick={() => navigate('home')}>Home</button>} /> // this works
      <Route path="/home" element={<Home authenticated={authenticated} />}></Route>
      <Route path="/auth" element={<Login signup={signup} login={login} />}></Route>
    </Routes>
  );
}

function AppWrapper() {
  return (
    <Router>
      <App />
    </Router>
  )
}

export default AppWrapper;
Poornaka
  • 180
  • 1
  • 13
  • Copy/pasted your code into this running [codesandbox](https://codesandbox.io/s/react-router-version-6-0-2-makes-page-unresponsive-reactjs-ircus) and the navigation from the `signup` callback appears to function. Can you double-check your code, ensure all code watchers/dev servers have been correctly restarted? – Drew Reese Nov 29 '21 at 20:23
  • 3
    You said it doesn't work when you add the navigate to a `useEffect`, but there's no `useEffect` uses in your code. Mind pasting the code that doesn't work? – Arthur Bruel Nov 29 '21 at 20:27
  • I edited it now – Poornaka Nov 29 '21 at 21:03

1 Answers1

2

My guess would be from the code that you are render looping since the useEffect hook is missing a dependency array. Each time App renders it looks like it recreates the auth listener and likely triggers a rerender.

Add the dependency array to the useEffect so it's only called once on component mount and return the unsubscribe function in the effect cleanup function.

useEffect(() => {
  const unsubscribe = onAuthStateChanged(auth, (user) => {
    if (user) {
      setAuthenticated(true);
      navigate('home');
    } else {
      setAuthenticated(false);
    }
  });

  return unsubscribe;
}, []); // <-- empty dependency == call once on mounting
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    This is perfect. What is the empty list passed in as a parameter for useEffect? – Poornaka Nov 29 '21 at 21:12
  • 1
    @Poornaka The second argument passed to the `useEffect` hook is an array of dependencies that can trigger the effect callback, i.e. when a dependency value changes the effect callback is called. An empty dependency array indicates there are no dependencies and so the effect should only run once when the component mounts. Without the second argument the effect callback runs each time the component is rendered. – Drew Reese Nov 29 '21 at 21:19