YES, I ALREADY ASKED TO CHATGPT.
i am using next js 15.2.3 and i implemented a spinner component that is activated when one navigation occurs, it is works! now i implemented a ThemeProvider (Context) for when the user select between dark mode or light mode. so… my spinner component doesnt paint its background with the theme selected by the user. only that spinner component, the others do take the theme.
below i share my code and then the chatgpt solutions that didn’t work for me:
app/layout.js:
import "./global.css";
export default function RootLayout({children}) {
return(
<html lang="en">
<body>
<ThemeProvider>
<GlobalLoader />
{children}
</ThemeProvider>
</body>
</html>
);
}
global.css
body.light {
--background: #fff;
--foreground: #000;
background: var(--background);
color: var(--foreground);
}
body.dark {
--background: #000;
--foreground: #fff;
background: var(--background);
color: var(--foreground);
}
ThemeProvider
"use client";
import { createContext, useContext, useEffect, useState } from "react";
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState(() => {
if (typeof window !== "undefined") {
const storedTheme = localStorage.getItem("theme");
if (storedTheme) return storedTheme;
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
return prefersDark ? "dark" : "light";
}
return "light";
});
useEffect(() => {
document.body.classList.remove("light", "dark");
document.body.classList.add(theme);
localStorage.setItem("theme", theme);
}, [theme]);
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export const useTheme = () => useContext(ThemeContext);
in my switch component to change the theme only i do:
const {theme, setTheme} = useTheme();
<input onChange((e) => e.target.checked ? "light" : "dark") />
it works! except the question…
GlobalLoader:
export default function GlobalLoader() {
const pathname = usePathname();
const [spinner, setSpinner] = useState(false);
useEffect(() => {
setSpinner(true);
const handleLoad = () => {
setSpinner(false);
};
const handleBeforeUnload = () => {
setSpinner(true);
};
window.addEventListener("load", handleLoad);
window.addEventListener("beforeunload", handleBeforeUnload);
return () => {
window.removeEventListener("load", handleLoad);
window.removeEventListener("beforeunload", handleBeforeUnload);
};
}, [pathname]);
if (spinner) return null;
return <Spinner/>;
Spinner:
export default function Spinner() {
return (
<section className={`${style.wrapper} ${style.dark}`}>
<div className={`${style.spinner}`}>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
</div>
</section>
);
Spinner.module.css
section.wrapper {
padding: 40px 0;
position: absolute;
width: 100%;
height: 100%;
z-index: 500;
}
section.wrapper.dark {
background: var(--background);
display: flex;
justify-content: center;
transition: background-color 1s ease;
}
at begin i had global.css like this:
:root {
/* light by default */
--background: #fff;
--foreground: #000;
}
@media(prefers-color-scheme: dark) {
--background: #000;
--foreground: #fff;
}
and works! my spinner component has background by default system ( win10 ), but i want that change with de user select-
GPT told me the problem is that my spinner component it build before the theme is apply on html tag or body tag. it suggested me to do below (no one suggestions works for me):
1: define a script that applies theme before it rendered:
<head>
<script dangerouslySetInnerHTML={{
__html: `
(function(){
const stored = localStorage.getItem("theme");
const theme = stored || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
document.documentElement.classList.add(theme);
})();
`,
}} />
</head>
2: apply the theme on html tag from my ThemeProvider:
useEffect(() => {
// ThemeProviderComponent
document.documentElement.classList.remove("light", "dark");
document.documentElement.classList.add(theme);
localStorage.setItem("theme", theme);
}, [theme]);
// changes global.css to:
html.light {
--background: #fff;
--foreground: #000;
background: var(--background);
color: var(--foreground);
}
html.dark {
--background: #000;
--foreground: #fff;
background: var(--background);
color: var(--foreground);
}
3: wait until my spinner it had mounted on my GlobalLoader:
// GlobalLoader
const [mounted, setMounted] = useState(false);
useEffect(()=>{
setMounted(true);
}, []);
...
if(!mounted) return null; // here it does not show my spinner
if(spinner) return null;
return <Spinner />
anomaly: if in this line if (spinner) return null
i deny with !: if (!spinner) return null
my spinner it will be showing forever with the background selected by the user, if it is select light or dark, it is draw… akward. ( i must select the theme before and then negate the state variable because it does not let me afterwards)
and that is all, i have no idea why this problem occurs…