admin管理员组

文章数量:1278653

I am new to NextJS and I was just trying things and I noticed that my dropdown component was not working as expected on the first load and I do not understand why that is happening. Basically, when I click on it, it does not work; like the click handler does not work and also the log in the dropdown component does not work on the client side despite the component being client component. But yes if I refresh the page everything works as expected. Below is all the code -: (and i am using NextJS 15 with app router)

This is my root layout -:

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import Header from "@/components/Header";
import Footer from "@/components/Footer";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased flex flex-col relative`}
      >
        <Header />
        <main className="bg-primaryBackground">
          {children}
        </main>

        <Footer />

      </body>
    </html>
  );
}

This is my Header Component -:

"use client";

import Link from "next/link";
import DropDown from "./DropDown";


export default function Header() {
    return (
        <header className="bg-secondaryBackground p-6 px-[22%] flex gap-10 justify-between items-center w-full sticky">

            <div className="flex justify-center items-center gap-6">
                <Link href={"/"} className="text-3xl font-extrabold">
                    Battlegrounds
                </Link>

                <DropDown label={"Change Game"}>

                    <li className="flex justify-between items-center border-gray-200 border-b border-opacity-10 px-11">
                        <Link href={''} className="py-4 w-full h-full">BGMI</Link>
                        <Link href={''} className="py-4 w-full h-full flex justify-end">COD</Link>
                    </li>

                    <li className="flex justify-between items-center px-11">
                        <Link href={''} className="py-4 w-full h-full">VALORANT</Link>
                        <Link href={''} className="py-4 w-full h-full flex justify-end">CSGO</Link>
                    </li>


                </DropDown>

            </div>


            <nav className="flex gap-8 justify-around items-center">


                <Link href={"/mybattles"} className="font-bold">My Battles</Link>
                <Link href={"/howitworks"} className="font-bold">How It Works</Link>
                <Link href={"/howitworks"} className="font-bold">
                    <svg
                        xmlns=";
                        fill="none"
                        viewBox="0 0 24 24"
                        strokeWidth={1.5}
                        stroke="currentColor"
                        className="size-6">

                        <path
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
                    </svg>
                </Link>


            </nav>

        </header>

    );
}

and this is my DropDown component -:

"use client";

import useOutsideClick from "@/Utils";
import React, { useRef, useState } from "react"
import DownArrowSingle from "./DownArrowSingle";

interface PropType {
    children: React.ReactNode,
    label: string,
    labelColor?: string,
    bgColor?: string,
}

export default function DropDown({ children, label, bgColor, labelColor }: PropType) {

    const [isVisible, setIsVisible] = useState<boolean>(false);
    const dropDownRef = useRef<HTMLDivElement | null>(null);

    const finalColor = bgColor || '#FFF';
    const finalLabelColor = labelColor || '#000';

    useOutsideClick(dropDownRef, isVisible, () => setIsVisible(false));

    console.log("IS DROPDOWN VISIBLE -> ", isVisible);

    return (
        <div
            ref={dropDownRef}
            style={{ backgroundColor: finalColor, color: finalLabelColor }}
            onClick={() => setIsVisible(prev => !prev)}
            className="cursor-pointer relative flex justify-center items-center gap-2 font-semibold rounded-full px-4 py-2 text-lg">

            {label}
            <DownArrowSingle />

            <ul
                onClick={e => e.stopPropagation()}
                className={`absolute ${isVisible ? 'flex' : 'hidden'} w-[400px] flex-col justify-start items-stretch left-0 top-[calc(100%+10px)] bg-[#0a0909] rounded-lg`}
            >
                {children}

            </ul>

        </div>
    )
}

Also this is my useOutsideClick hook

import { useEffect } from "react";

function useOutsideClick<T extends HTMLElement>(ref: React.RefObject<T | null>, isShowing: boolean, callback: () => void) {
    useEffect(() => {

        function handleClickOutside(event: globalThis.MouseEvent) {
            if (ref.current && !ref.current.contains(event.target as Node)) {
                if (isShowing) {
                    callback();
                }
            }
        }

        document.addEventListener("mousedown", handleClickOutside);

        return () => {
            document.removeEventListener("mousedown", handleClickOutside);
        };

    }, [isShowing]);
}

export default useOutsideClick;

I tried using ChatGPT but it is not of much help.

本文标签: reactjsClient component not getting rendered on first load in NextJSStack Overflow