Búsqueda de sitios web

javascript - Ejecutando una aplicación Next.js en modo de desarrollo, ocurre un error en tiempo de ejecución que dice "ReferenceError: Cannot access X before initialization"


Estoy usando la versión 13.4 de next.js. Creé un Provider usando ContextAPI en React (digamos que es AuthContext) y envuelvo toda la aplicación con él en el componente RootLayout. El RootLayout está ubicado en app/layout.tsx.

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <GlobalErrorBoundary>
          <AuthProvider>{children}</AuthProvider>
        </GlobalErrorBoundary>
      </body>
    </html>
  );
}

No hay error en el tiempo de compilación, pero cuando ejecuto npm run dev, el navegador indicó que ocurre un "Error de tiempo de ejecución no manejado". Y decía, "ReferenceError: Cannot access 'AuthContext' before initialization".

Cuando construyo la aplicación y npm run start, funciona bien. Solo sucede cuando ejecuto npm run dev. Lo peor es que este error en tiempo de ejecución ocurre de forma aleatoria, bastante a menudo, sin embargo.

Cuando miro en la herramienta de desarrollo de React, hay un error en ReactDevOverlay, que tiene un hijo llamado <DevRootNotFoundBoundary />. El mensaje de error dice: "El error anterior ocurrió en el componente".

Editar:

Aquí hay una versión simple del código Auth.tsx (para declarar ContextAPI):

"use client";

export const AuthContext =
    createContext<AuthContextType | null>(null);

export const AuthProvider = ({
    children,
}: PropsWithChildren) => {
    const [token, setToken] =
        useStateWithLocalStorage<AuthTokenType>("token");
    const newToken = useTokenRefresh(token);

    useEffect(() => {
        if (newToken === undefined) {
            return;
        }

        setToken(newToken);
    }, [newToken]);

    useMemo(() => {
        if (token === null) {
            return;
        }
        addTokenToHttpClient(token);
    }, [token]);

    return (
        <AuthContext.Provider
            value={{
                token,
                setToken,
            }}
        >
            {children}
        </AuthContext.Provider>
    );
};

export const useAuthContext = () => {
    const context: AuthContextType | null = useContext(
        AuthContext
    );

    if (context === null) {
        throw new Error();
    }

    return context;
};

Quizás quieras conocer el interior de useStateWithLocalStorage usado arriba. Los posibles errores que ocurren al referirse a localStorage en el servidor están cubiertos por la lógica a continuación.

if (typeof window !== "undefined") {
    return localStorage.getItem(key);
}

Editar:

Encontré un punto sospechoso en la base de código, pero no puedo averiguar la razón exacta de ello. ¿Alguien puede ayudarme con esto?

Mi archivo Auth.tsx está en el directorio app/contexts/withLocalStorage/. Dentro de este directorio hay 2 archivos de Context diferentes además del archivo Auth.tsx y, además, un archivo index.ts. Todas las variables de los archivos de Context se exportan a través de index.ts.

A continuación está index.ts.

"use client";

export * from "./Example1";
export * from "./Example2";
export * from "./Auth";

La única diferencia en Auth y los otros 2 archivos de ejemplo es que, en Auth.tsx, se está usando useEffect y useMemo. Cuando comento la línea sobre export * from "./Auth"; en index.ts, ¡el ERROR DESAPARECE!.

Parece que index.ts está intentando importar módulos en el lado del servidor. Pero un archivo de Contexto que use la API del lado del cliente de React aún no se ha creado en ese momento. La directiva "use client"; en index.ts no funciona en este caso. ¿Pero por qué? O si es así, ¿existe alguna solución para usar useEffect o useMemo en archivos de contexto?