Reputation: 334
I'm trying to create a dark mode toggle in React and TailwindCSS for my web page, and have been following this tutorial: https://omerduraker.medium.com/dark-and-light-mode-using-react-tailwind-css-58bb8f988080.
The tutorial worked fine, however when I tried to change the default behaviour to default to dark mode rather than light mode, I have been running into issues, I presume with states not updating? The tutorial uses localStorage to save the chosen colour mode preference, however when you first visit the page, as there is no localStorage value present, it only retrieves the value 'undefined' meaning that the application defaults to light mode. The issue primarily pertains to behaviour on first loading of the website, once you have a valid localStorage value, it works fine!
Here is the code I have been trying to use to override this behaviour, but while I can override the page to dark mode, my toggle switch is staying stuck in the position it would be if the page were in light mode. I have provided a screenshot highlighting the issue below. Can anyone see what I'm doing wrong? Thanks!
This should show a white moon icon, not a black sun.
Looking in React developer tools, it appears the state is not updating. The state highlighted should be true, but is unfortunately showing false for some reason.
useDarkMode.tsx:
import React, { useEffect, useState } from "react";
export default function useDarkMode() {
const [theme, setTheme] = useState(localStorage.theme);
if (typeof theme === 'undefined') {
setTheme('dark');
}
const colourTheme = theme === 'dark' ? 'light' : ('light' ? 'dark' : 'light');
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove(colourTheme);
root.classList.add(typeof theme === 'undefined' ? 'dark' : theme);
localStorage.setItem('theme', typeof theme === 'undefined' ? 'dark' : theme);
}, [theme, colourTheme]);
return [colourTheme, setTheme] as any;
}
nav.tsx
export default function Nav(props: any) {
const [colourtheme, setTheme] = useDarkMode();
const [isDarkMode, setDarkMode] = useState(
colourtheme === "dark" ? true : false
);
const dmProps = {
colourtheme: colourtheme,
setTheme: setTheme,
isDarkMode: isDarkMode,
setDarkMode: setDarkMode,
};
....
<Switcher className="flex flex-col ml-2 mr-1.5 md:flex-row md:space-x-8 md:mt-0" functions={dmProps} />
switcher.tsx
import React, { useState } from 'react';
import { DarkModeSwitch } from 'react-toggle-dark-mode';
export default function Switcher(props: any) {
function toggleDarkMode(checked: boolean):void {
props.functions.setTheme(props.functions.colourtheme);
props.functions.setDarkMode(checked);
}
return (
<div className={`flex flex-col items-center w-auto ${props.className}`}>
<DarkModeSwitch
style={{ }}
checked={props.functions.isDarkMode}
onChange={toggleDarkMode}
size={25}
/>
</div>
);
};
Upvotes: 0
Views: 63
Reputation: 7305
I'm not sure where the localstate
object used as the default in your useState
is coming from. Ordinarily, you would use localstorage.getItem('theme')
to retrieve this value. This getItem
function call should not return undefined
, since it defaults to null
if the key (e.g. 'theme') is not found.
See: https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem
Also, you may want to refactor your double ternary:
const colourTheme = theme === 'dark' ? 'light' : ('light' ? 'dark' : 'light');
The second ternary (in parenthesis) will always return 'dark', since the condition, 'light' is equivalent to true
.
Upvotes: 2