I am building a small web application with react and have also included a ThemeSwitcher component. This component contains the visual aspects, i.e. the toggle, as well as a script to switch the theme and a script to access local storage. The ThemeSwitcher component then gets imported into the Header component, which in turn gets imported into index.js
When toggling from the dark-theme (default) to the light-theme, this information is saved to local storage:
let currentTheme = "dark-theme";
function switchTheme() {
const body = document.querySelector("body");
const transitionChecker = document.querySelector("#theme-selector");
body.classList.add("transition");
body.classList.toggle("light-theme");
transitionChecker.addEventListener("transitionend", () => {
body.classList.remove("transition");
});
currentTheme === "dark-theme"
? (currentTheme = "light-theme")
: (currentTheme = "dark-theme");
localStorage.setItem("storedTheme", currentTheme);
}
I am accessing this value on page load using:
window.addEventListener("load", function () {
let storedTheme = localStorage.getItem("storedTheme");
if (storedTheme === "light-theme") switchTheme();
});
This works more or less as intended. However, on page load the dark-theme is shown for a split second, before switching over to the light-theme.
Is there any way to grab the intended theme before the page is rendered in order to avoid the default theme from flashing through?
So after some playing around, I believe to have a solution that works for me. I basically just put this right at the beginning of my App.js (which gets rendered in index.js) just before declaring the actual component:
//get stored theme right at the beginning
let currentTheme = localStorage.getItem("storedTheme");
if (!currentTheme) currentTheme = "dark-theme"; // if no theme was stored, set to default --> dark-theme
document.querySelector("body").classList.add(currentTheme);
How I arrived at this solution:
useEffect()
, but this still let the dark theme flash
through if the light-theme chosen previouslyswitchTheme()
was also moved to App.js and is located at the very end.
Not sure if this is a proper solution or if it just gives the browser this extra split second to grab the stored theme before it actually gets rendered. But it worked for me.