I'm trying to make a light / dark theme . And I have 2 components. The first component is the one below. I succeeded to make a boolean to change my style in my component. It was good so far :
export interface Props{
theme:boolean;
}
const Theme: FC<Props> = ({theme}) => {
const [light,setLightMode]=useState(false);
return (
<div>
<div className="card__theme">
<div className={light ? "card__light" : "card__light--active"}>Light</div>
<Switch inputProps={{ "aria-label": "controlled" }} onChange={()=>setLightMode(!light)}/>
<div className={ light ? "card__Dark" : "card__Dark--active"}>Dark</div>
</div>
</div>
);
};
What I do right now is to use this component in my Home page where I want to do the same thing. I want to change the style of my components , making 2 className like the code above with a boolean state. The problem that I'm facing is that I can't make another function onChange={} in my home component. First I don't send in interface a function . I want my const [light,setLightMode]=useState(false); and my function onChange={()=>setLightMode(!light)} when I switch the button to work in my Home component from below
const Home: FC = () => {
const percentage = 91;
const [dark,setDark] = useState(false);
return (
<div>2
<div className="Container-body">
<div className="card">
<div className={dark ? "card__theme" : "card__theme--active"}>
<Theme theme={dark} onChange={()=>{setDark(!dark)}}/>
</div>
So to make it sort. I want to use just the light, setlightTheme boolean state from my Theme component in my Home component . I don't know how I can send this with props in TypeScript...
Here is a print with my code : enter link description here
CodePudding user response:
I'm not sure if I understand correctly, but I think your goal is to pass the onChange function to the Theme component from the parent component. If so, I hope this snippet can help you. Basically I added the onChange parameter in the interface as a function. I also renamed the theme parameter to dark. To make the two components work together, I removed the useState in the Theme component and used the dark variable (taken from the parent component) to manage the styles.
export interface Props {
dark: boolean;
onChange?: () => void;
}
const Theme: FC<Props> = ({ dark, onChange }) => {
return (
<div>
<div className="card__theme">
<div className={dark ? 'card__light' : 'card__light--active'}>
Light
</div>
<Switch
inputProps={{ 'aria-label': 'controlled' }}
onChange={onChange}
/>
<div className={!dark ? 'card__Dark' : 'card__Dark--active'}>Dark</div>
</div>
</div>
);
};
CodePudding user response:
So if I understand correctly you just want to provide an option for switching light and dark mode. From an architectural point of view you don't want to do this on a component-level since multiple component might need to change.
BEM Mistake
Before I address a proper solution you are currently making a BEM mistake with this line:
<div className={dark ? 'card__light' : 'card__light--active'}>
A modifier --modifier
can only live together with an actual element card
. So on a fully outputted HTML this is valid card__light card__light--active
but in your example either card__light
or card__light--active
is being rendered.
Solution for theme switching
When it comes down to switching a dark/light theme you either want to make this value (true or false) available in a centralised state by using something like Redux or you might want to declare it on your root component (most often the <App />
) and start using it from there.
I don't recommend prop drilling for this use case since it will make your code messy in the long run. This is a really nice use case for the Context API.
✅ See working example Playground.
P.s. I use Typescript for better code, you can ignore the syntax you don't know.
React documentation
The React documentation has an exact example for you see docs theme switching.