javascriptnode.jsreactjsreact-hookslifecycle

Why useEffect gets executed before child components rendered?


I have unexpected behaviour. The user variable that I declared at the top of my App component is null by default.

At the first start or refresh of path=/, useEffect of the App component gets executed before child component which is Login. What is the reason for this behaviour?

App.js:

import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { useAuthContext } from './hooks/useAuthContext'
import { useEffect }from 'react'

// pages & components
import Home from './pages/Home'
import Login from './pages/Login'
import Signup from './pages/Signup'
import Navbar from './components/Navbar'

function App() {
  const { user } = useAuthContext()

  useEffect(() => {
    console.log("App useffect")
  }, [])

  return (
    <div className="App">
      <BrowserRouter>
        <Navbar />
        <div className="pages">
        {console.log("Route main")}
          <Routes>
            <Route 
              path="/"
              element={user ? <Home /> : <Navigate to="/login" /> } 
            />
            <Route 
              path="/login" 
              element={!user ? <Login /> : <Navigate to="/" />} 
            />
            <Route 
              path="/signup" 
              element={!user ? <Signup /> : <Navigate to="/" />} 
            />
          </Routes>
        </div>
      </BrowserRouter>
    </div>
  );
}

export default App;

Login.js:

import { useEffect } from 'react'

const Login = () => {
  console.log('Login here:')

  useEffect(() => {
    console.log("Login here:' useffect")
  }, [])

  return (
        <div>Login</div>
  )
}

export default Login

Solution

  • This is what <Navigate /> simply looks like,

    function Navigate() {
      React.useEffect(
        () => navigate(JSON.parse(jsonPath), { replace, state, relative }),
        [navigate, jsonPath, relative, replace, state]
      );
    
      return null;
    }
    

    It also uses a useEffect to handle the side-effect ( replace the url ) and the render phase of the <Navigate /> returns just null.

    So it works as expected. It renders your App, then It renders your <Navigate /> which returns null. Rendering completed and then it executed the side effects. Then after all of that, the side effect in the <Navigate /> is the one which causes to render <Login /> page.