I am using @clerk/nextjs": "^4.29.5"
for the authentication system for my next.js 14
app. I am managing some global states using context-api. My problem is when I revisit my home route (/) the page is fully reloading instead of soft navigation (other routes are ok). This only happens in the hosted (vercel)
app, not in the localhost or even when I run the build version using npm start
. How to fix this issue? What I'm doing wrong here? I don't want to reload my whole page.
Project structure:
app/
(auth)
layout.tsx
sign-in/
sign-up/
(root)
layout.tsx
page.tsx
layout.tsx
layout.ts:
import { MainContextProvider } from "@/contexts/MainContext";
import ClerkThemeProvider from "@/lib/providers/ClerkThemeProvider";
import { Suspense } from "react";
import MainPageFallback from "@/components/shared/MainPageFallback";
import { Toaster } from "@/components/ui/toaster";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className={`${inter.className}`}>
<MainContextProvider>
<Suspense fallback={<MainPageFallback />}>
<ClerkThemeProvider>{children}</ClerkThemeProvider>
</Suspense>
</MainContextProvider>
<Toaster />
</body>
</html>
);
}
/contexts/MainContext.ts:
"use client";
import { createContext, useEffect, useState } from "react";
export const MainContext = createContext({
lang: "",
theme: "",
sidebarOpen: false,
handleLang: () => {},
changeTheme: () => {},
closeSidebar: () => {},
openSidebar: () => {},
});
export const MainContextProvider = ({ children }: { children: React.ReactNode }) => {
const [lang, setLang] = useState("en");
const [theme, setTheme] = useState("light");
const [sidebarOpen, setSidebarOpen] = useState(false);
useEffect(() => {
const savedTheme = localStorage.getItem("theme");
const savedLang = localStorage.getItem("lang");
setLang(savedLang ? savedLang : "en");
setTheme(savedTheme ? savedTheme : "light");
}, []);
useEffect(() => {
localStorage.setItem("lang", lang);
document.documentElement.lang = lang;
}, [lang]);
useEffect(() => {
localStorage.setItem("theme", theme);
if (theme === "dark") {
document.body.classList.add("dark");
} else {
document.body.classList.remove("dark");
}
}, [theme]);
const handleLang = () => {
setLang(lang === "en" ? "bn" : "en");
};
const changeTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
const openSidebar = () => {
setSidebarOpen(true);
};
const closeSidebar = () => {
setSidebarOpen(false);
};
return (
<MainContext.Provider
value={{
lang,
theme,
sidebarOpen,
handleLang,
openSidebar,
changeTheme,
closeSidebar,
}}
>
{children}
</MainContext.Provider>
);
};
/lib/providers/ClerkThemeProvider.tsx
"use client";
import { MainContext } from "@/contexts/MainContext";
import { ClerkProvider } from "@clerk/nextjs";
import { dark } from "@clerk/themes";
import { useContext } from "react";
export default function ClerkThemeProvider({ children }: { children: React.ReactNode }) {
const { theme } = useContext(MainContext);
return (
<ClerkProvider appearance={{ baseTheme: theme === "dark" ? dark : undefined }}>
{children}
</ClerkProvider>
);
}
middleware.ts
import { authMiddleware } from "@clerk/nextjs";
export default authMiddleware({
// An array of public routes that don't require authentication.
publicRoutes: ["/", "/about", "/contact", "/api/webhooks(.*)", "/api/uploadthing"],
// An array of routes to be ignored by the authentication middleware.
ignoredRoutes: ["/api/webhooks(.*)"],
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
I solved the issue. I want to share it. It's a straightforward cause, why the home route always fully reloads on the deployed version. It's none of the clerk
package cause.
I just had to add a loading.tsx
file on the app/
folder and then the full reload will not occur anymore.