Search code examples
reactjsreact-routeroauthreact-router-dom

Why does my React App.js gets render 3 times only on page refresh?


I am not sure why the return statements within App.js gets called 3 times during page refreshes.

My Index.js:

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";

import "assets/plugins/nucleo/css/nucleo.css";
import "@fortawesome/fontawesome-free/css/all.min.css";
import "assets/scss/argon-dashboard-react.scss";

import { Auth0ProviderWithNavigate } from "./auth0-provider-with-navigate";
import { App } from "./app";
import store from "./app/store";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <BrowserRouter>
    <Auth0ProviderWithNavigate>
      <Provider store={store}>
        {console.log("Hit from Index")}
        <App />
      </Provider>
    </Auth0ProviderWithNavigate>
  </BrowserRouter>
);

My App.js

import { useAuth0 } from "@auth0/auth0-react";
import React, { useEffect } from "react";
import { Route, Routes } from "react-router-dom";
import { AuthenticationGuard } from "./components/authentication-guard";
import Admin from "layouts/Admin.js";
import Auth from "layouts/Auth.js";

export const App = () => {
  const { isLoading } = useAuth0();

  useEffect(() => {
    console.log("Hit from App UseEffect");
  }, []);

  return (
    <>
      {console.log("Hit from App Return", isLoading)}{" "}
      {isLoading ? (
        <div className="page-layout">
          <Auth />
        </div>
      ) : (
        <Routes>
          <Route path="/" element={<Auth />} exact />
          <Route path="/auth/*" element={<Auth />} />
          <Route
            path="/admin/*"
            element={<AuthenticationGuard component={Admin} />}
          />
        </Routes>
      )}
    </>
  );
};

console.log results

When I first load the page via login the return statements within App.js gets called 2 times (expected) however if I were to refresh the page it gets called 3 times whereas I expected 2.


Solution

  • You appear to have some confusion about what your logs mean. You are console logging as an unintentional side-effect in the App component's return statement, so any "expected behavior" should be thrown out the window. React can "render" your component, e.g. call the function, as many times as it needs to in order to compute what needs to be committed to the DOM.

    Always use the useEffect hook to log data so you have a one-to-one relation between render (to the DOM) and an effect.

    export const App = () => {
      const { isLoading } = useAuth0();
    
      useEffect(() => {
        console.log("Mounting App useEffect");
      }, []); // <-- run once when component mounted/initial render
    
      useEffect(() => {
        console.log("Render App to the DOM useEffect");
      }); // <-- no dependency, run once each render
    
      useEffect(() => {
        console.log("useEffect because isLoading updated", isLoading);
      }, [isLoading]); // <-- run only when isLoading updates
    
      return (
        <>
          {isLoading ? (
            <div className="page-layout">
              <Auth />
            </div>
          ) : (
            <Routes>
              <Route path="/" element={<Auth />} exact />
              <Route path="/auth/*" element={<Auth />} />
              <Route
                path="/admin/*"
                element={<AuthenticationGuard component={Admin} />}
              />
            </Routes>
          )}
        </>
      );
    };