Search code examples
reactjsnext.jsreact-hooksreact-context

Next.js - useEffect doesn't execute even once


I've been working on implementing socket.io into my Next.js application and have been running into some issues I've been having a hard time deciphering the source of, so I've figured I'll deduct my code to the absolute base and slowly start adding pieces until I figure it out. I've done that and it only got more confusing.

I keep my socket in a context provider which is a direct child of the body tag in my root layout file, so it'll wrap my entire app (my issues with the socket were that I kept getting infinite "connection made" events. I'd console log when a connection was made and I'd keep having a new one every few seconds. So keeping it as the main parent seems like the best approach to eliminate any external causes for re-renders).

Anyway, in my context provider, I've stripped out everything to do with anything, so I could follow my "plan" to slowly add things back.

This is my layout file:

import { SocketProvider } from "../hooks/useSocket";
import "./globals.css";

export const metadata = {
  title: "Title",
  description: "Description",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <SocketProvider>
          <>{children}</>
        </SocketProvider>
      </body>
    </html>
  );
}

This is my home page:

import { Inter } from "next/font/google";

const inter = Inter({ subsets: ["latin"] });

export default function Home() {
  return (
    <main className="relative h-full flex-grow">
      <p>empty page</p>
    </main>
  );
}

And this is my context provider:

"use client";

import React, {
  createContext,
  useContext,
  useEffect,
} from "react";

type SocketContextProps = {
};

const SocketContext = createContext<SocketContextProps>({
});

export const SocketProvider = ({ children }: { children: JSX.Element }) => {
  console.log(
    "******************* render socket provider *******************"
  );

  useEffect(() => {
    console.log(
      "******************* socket provider useEffect *******************"
    );
  }, []);



  return (
    <SocketContext.Provider value={{}}>
      {children}
    </SocketContext.Provider>
  );
};

export default function useSocket() {
  return useContext(SocketContext);
}

The issue: I get this log "******************* render socket provider *******************" printing 3 times

This log ******************* socket provider useEffect ******************* doesn't print even once

EDIT: So I've decided to add a useEffect inside my root (home) page, to see if it helps me understand anything better somehow. This useEffect didn't run either!

This is my new home page:

"use client";

import { useEffect } from "react";

export default function GameHome() {
  console.log("^^^^^^^ Home Page ^^^^^^^^^");

  useEffect(() => {
    console.log("$$$$$$$$ Home page useEffect $$$$$$$$$$");
  }, []);

  return (
    <main className="relative h-full flex-grow">
      <p>empty page</p>
    </main>
  );
}

This is what I get in my console

wait  - compiling...
wait  - compiling /[game-slug]/page (client and server)...
event - compiled client and server successfully in 6.1s (634 modules)
******************* render socket provider *******************
******************* render socket provider *******************
^^^^^^^ Home Page ^^^^^^^^^
******************* render socket provider *******************

Solution

  • NextJS is giving you control on whether you want to run your code on browser or in server. It is simple when its under API folder as its then always on the server, but complicated when talking about React components.

    By default, nextJS does a hybrid on which there is CSR (Client side rendered aka browser) and SSR (Server side rendered, so in this case, your console). It renders the react component beforehand, executing all the code that ISN'T lifecycle relevant. So in other words, does as much as it can before shipping it to user.

    Since useEffect is lifecycle method, it doesn't get executed on the server but gets shipped alongside the HTML and CSS necessary to the browser where it executes.

    I would recommend you to use API folder if you want to have server side logic running. If you want to have it in UI components, NextJS luckily gives you some control! I suggest you the following reading as they do better job explaining than I ever would:

    NextJS fundamentals of the rendering: https://beta.nextjs.org/docs/rendering/fundamentals

    Basic features on making SSG or SSR work: https://nextjs.org/docs/basic-features/pages

    Server and client side components (the future way, most likely): https://beta.nextjs.org/docs/rendering/server-and-client-components