clerk / javascript

Official Javascript repository for Clerk authentication
https://clerk.com
MIT License
1.11k stars 245 forks source link

I'm getting "Error: Should have a queue. This is likely a bug in React. Please file an issue." this error while wrapping my app with clerk provider #3765

Closed fzkhan19 closed 2 months ago

fzkhan19 commented 2 months ago

Preliminary Checks

Reproduction

https://github.com/fzkhan19/Modernized-Takeoff.git

Publishable key

pk_test_ZXRlcm5hbC1vd2wtMTkuY2xlcmsuYWNjb3VudHMuZGV2JA

Description

I have this component:

Particles.tsx

"use client";

import type React from "react";
import { useEffect, useRef, useState } from "react";

interface MousePosition {
    x: number;
    y: number;
}

function MousePosition(): MousePosition {
    const [mousePosition, setMousePosition] = useState<MousePosition>({
        x: 0,
        y: 0,
    });

    useEffect(() => {
        const handleMouseMove = (event: MouseEvent) => {
            setMousePosition({ x: event.clientX, y: event.clientY });
        };

        window.addEventListener("mousemove", handleMouseMove);

        return () => {
            window.removeEventListener("mousemove", handleMouseMove);
        };
    }, []);

    return mousePosition;
}

interface ParticlesProps {
    className?: string;
    quantity?: number;
    staticity?: number;
    ease?: number;
    size?: number;
    refresh?: boolean;
    color?: string;
    vx?: number;
    vy?: number;
}
function hexToRgb(hex: string): number[] {
    const cleanHex = hex.replace("#", "");
    const hexInt = Number.parseInt(cleanHex, 16);
    const red = (hexInt >> 16) & 255;
    const green = (hexInt >> 8) & 255;
    const blue = hexInt & 255;

    return [red, green, blue];
}

const Particles: React.FC<ParticlesProps> = ({
    className = "",
    quantity = 100,
    staticity = 50,
    ease = 50,
    size = 0.4,
    color = "#0099dd",
    refresh = false,
    vx = 0,
    vy = 0,
}) => {
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const canvasContainerRef = useRef<HTMLDivElement>(null);
    const context = useRef<CanvasRenderingContext2D | null>(null);
    // biome-ignore lint/suspicious/noExplicitAny: <explanation>
    const circles = useRef<any[]>([]);
    const mousePosition = MousePosition();
    const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
    const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
    const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;

    // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
    useEffect(() => {
        if (canvasRef.current) {
            context.current = canvasRef.current.getContext("2d");
        }
        initCanvas();
        animate();
        window.addEventListener("resize", initCanvas);

        return () => {
            window.removeEventListener("resize", initCanvas);
        };
    }, [color]);

    // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
    useEffect(() => {
        onMouseMove();
    }, [mousePosition.x, mousePosition.y]);

    // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
    useEffect(() => {
        initCanvas();
    }, [refresh]);

    const initCanvas = () => {
        resizeCanvas();
        drawParticles();
    };

    const onMouseMove = () => {
        if (canvasRef.current) {
            const rect = canvasRef.current.getBoundingClientRect();
            const { w, h } = canvasSize.current;
            const x = mousePosition.x - rect.left - w / 2;
            const y = mousePosition.y - rect.top - h / 2;
            const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;

            if (inside) {
                mouse.current.x = x;
                mouse.current.y = y;
            }
        }
    };

    type Circle = {
        x: number;
        y: number;
        translateX: number;
        translateY: number;
        size: number;
        alpha: number;
        targetAlpha: number;
        dx: number;
        dy: number;
        magnetism: number;
    };

    const resizeCanvas = () => {
        if (canvasContainerRef.current && canvasRef.current && context.current) {
            circles.current.length = 0;
            canvasSize.current.w = canvasContainerRef.current.offsetWidth;
            canvasSize.current.h = canvasContainerRef.current.offsetHeight;
            canvasRef.current.width = canvasSize.current.w * dpr;
            canvasRef.current.height = canvasSize.current.h * dpr;
            canvasRef.current.style.width = `${canvasSize.current.w}px`;
            canvasRef.current.style.height = `${canvasSize.current.h}px`;
            context.current.scale(dpr, dpr);
        }
    };

    const circleParams = (): Circle => {
        const x = Math.floor(Math.random() * canvasSize.current.w);
        const y = Math.floor(Math.random() * canvasSize.current.h);
        const translateX = 0;
        const translateY = 0;
        const pSize = Math.floor(Math.random() * 2) + size;
        const alpha = 0;
        const targetAlpha = Number.parseFloat(
            (Math.random() * 0.6 + 0.1).toFixed(1),
        );
        const dx = (Math.random() - 0.5) * 0.1;
        const dy = (Math.random() - 0.5) * 0.1;
        const magnetism = 0.1 + Math.random() * 4;

        return {
            x,
            y,
            translateX,
            translateY,
            size: pSize,
            alpha,
            targetAlpha,
            dx,
            dy,
            magnetism,
        };
    };

    const rgb = hexToRgb(color);

    const drawCircle = (circle: Circle, update = false) => {
        if (context.current) {
            const { x, y, translateX, translateY, size, alpha } = circle;

            context.current.translate(translateX, translateY);
            context.current.beginPath();
            context.current.arc(x, y, size, 0, 2 * Math.PI);
            context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`;
            context.current.fill();
            context.current.setTransform(dpr, 0, 0, dpr, 0, 0);

            if (!update) {
                circles.current.push(circle);
            }
        }
    };

    const clearContext = () => {
        if (context.current) {
            context.current.clearRect(
                0,
                0,
                canvasSize.current.w,
                canvasSize.current.h,
            );
        }
    };

    const drawParticles = () => {
        clearContext();
        const particleCount = quantity;

        for (let i = 0; i < particleCount; i++) {
            const circle = circleParams();

            drawCircle(circle);
        }
    };

    const remapValue = (
        value: number,
        start1: number,
        end1: number,
        start2: number,
        end2: number,
    ): number => {
        const remapped =
            ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;

        return remapped > 0 ? remapped : 0;
    };

    const animate = () => {
        clearContext();
        circles.current.forEach((circle: Circle, i: number) => {
            // Handle the alpha value
            const edge = [
                circle.x + circle.translateX - circle.size, // distance from left edge
                canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge
                circle.y + circle.translateY - circle.size, // distance from top edge
                canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
            ];
            const closestEdge = edge.reduce((a, b) => Math.min(a, b));
            const remapClosestEdge = Number.parseFloat(
                remapValue(closestEdge, 0, 20, 0, 1).toFixed(2),
            );

            if (remapClosestEdge > 1) {
                circle.alpha += 0.02;
                if (circle.alpha > circle.targetAlpha) {
                    circle.alpha = circle.targetAlpha;
                }
            } else {
                circle.alpha = circle.targetAlpha * remapClosestEdge;
            }
            circle.x += circle.dx + vx;
            circle.y += circle.dy + vy;
            circle.translateX +=
                (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) /
                ease;
            circle.translateY +=
                (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) /
                ease;

            drawCircle(circle, true);

            // circle gets out of the canvas
            if (
                circle.x < -circle.size ||
                circle.x > canvasSize.current.w + circle.size ||
                circle.y < -circle.size ||
                circle.y > canvasSize.current.h + circle.size
            ) {
                // remove the circle from the array
                circles.current.splice(i, 1);
                // create a new circle
                const newCircle = circleParams();

                drawCircle(newCircle);
                // update the circle position
            }
        });
        window.requestAnimationFrame(animate);
    };

    return (
        <div ref={canvasContainerRef} aria-hidden="true" className={className}>
            <canvas ref={canvasRef} className="h-full w-full" />
        </div>
    );
};

export default Particles;

And I'm getting the error exactly at const [mousePosition, setMousePosition] = useState<MousePosition>({ x: 0, y: 0, });

The app/layout.tsx consists of this code:

import Providers from "@/components/layout/Providers";
import Footer from "@/components/layout/footer";
import { Navbar } from "@/components/layout/navbar";
import { JSON_LD, METADATA } from "@/constants/Metadata";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

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

export const metadata: Metadata = METADATA;

export default function RootLayout({
    children,
}: Readonly<{
    children: React.ReactNode;
}>) {
    return (
        <html lang="en" suppressHydrationWarning>
            <body className={inter.className}>
                <Providers>
                    <Navbar />
                    <main className="overflow-x-hidden overflow-y-scroll scroll-smooth no-scrollbar p-0 m-0">
                        <script
                            // biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
                            dangerouslySetInnerHTML={{ __html: JSON.stringify(JSON_LD) }}
                            type="application/ld+json"
                        />
                        {children}
                    </main>
                    <footer>
                        <Footer />
                    </footer>
                </Providers>
            </body>
        </html>
    );
}

Providers.tsx is this:

import type { ReactNode } from "react";

import { ClerkProvider } from "@clerk/nextjs";
import QueryProviders from "./query-client-provider";
import { ThemeProvider } from "./theme-provider";
const Providers = ({ children }: { children: ReactNode }) => {
    return (
        <ThemeProvider
            disableTransitionOnChange
            enableSystem
            attribute="class"
            defaultTheme="system"
        >
            <ClerkProvider
                appearance={{
                    variables: {
                        colorPrimary: "hsl(221.2 83.2% 53.3%)",
                    },
                }}
            >
                <QueryProviders>{children}</QueryProviders>
            </ClerkProvider>
        </ThemeProvider>
    );
};

export default Providers;

Environment

System:
    OS: Windows 11 10.0.22631
    CPU: (12) x64 12th Gen Intel(R) Core(TM) i5-12450H
    Memory: 1.23 GB / 7.65 GB
  Binaries:
    Node: 20.13.1 - C:\Program Files\nodejs\node.EXE
    npm: 10.5.2 - C:\Program Files\nodejs\npm.CMD
    pnpm: 9.1.0 - C:\Program Files\nodejs\pnpm.CMD
    bun: 1.1.12 - ~\.bun\bin\bun.EXE
  Browsers:
    Edge: Chromium (126.0.2592.87)
    Internet Explorer: 11.0.22621.3527
  npmPackages:
    @biomejs/biome: 1.8.3 => 1.8.3
    @clerk/nextjs: ^5.2.4 => 5.2.4
    @million/lint: ^1.0.0-rc.81 => 1.0.0-rc.81
    @radix-ui/react-dialog: ^1.1.1 => 1.1.1
    @radix-ui/react-navigation-menu: ^1.2.0 => 1.2.0
    @radix-ui/react-separator: ^1.1.0 => 1.1.0
    @radix-ui/react-slot: ^1.1.0 => 1.1.0
    @tanstack/react-query: ^5.51.9 => 5.51.9
    @types/node: ^20.14.11 => 20.14.11
    @types/react: ^18.3.3 => 18.3.3
    @types/react-dom: ^18.3.0 => 18.3.0
    class-variance-authority: ^0.7.0 => 0.7.0
    clsx: ^2.1.1 => 2.1.1
    husky: ^9.1.0 => 9.1.0
    lint-staged: ^15.2.7 => 15.2.7
    lucide-react: ^0.408.0 => 0.408.0
    next: ^14.2.5 => 14.2.5
    next-themes: ^0.3.0 => 0.3.0
    postcss: ^8.4.39 => 8.4.39
    react: ^18.3.1 => 18.3.1
    react-dom: ^18.3.1 => 18.3.1
    tailwind-merge: ^2.4.0 => 2.4.0
    tailwindcss: ^3.4.6 => 3.4.6
    tailwindcss-animate: ^1.0.7 => 1.0.7
    typescript: ^5.5.3 => 5.5.3
LekoArts commented 2 months ago

Hi! This issue tracker is for problems with Clerk, when you put the error into Google you'll see that it must come from your code, e.g. https://stackoverflow.com/questions/65548028/error-should-have-a-queue-this-is-likely-a-bug-in-react-please-file-an-issue