Leonardo Carlassare
Leonardo Carlassare

Reputation: 27

Cannot switch to Darkmode using React Typescript Redux

I implemented a Redux state that stores the boolean value 'isDarkmode': this value changes properly when I click the button, from true to false and viceversa so I implemented redux correctly, I'm sure of it. The problem is that my component SubHeader doesn't change style when I click the button. I report the code below. For example, neither the background or the div below are changing color. Where am I wrong?

SubHeader.tsx

import styles from './SubHeader.module.scss'
import Image from 'next/image'
import sunPic from '../../public/svg/sun.svg'
import { useRouter } from 'next/router'

import { toggleDarkmode } from '../../redux/slices/darkmodeSlice'
import { useAppSelector, useAppDispatch } from '../../redux/hooks'
import { useEffect } from 'react'

 export default function SubHeader() {

    const router = useRouter();
    const isDarkmode = useAppSelector((state) => state.darkmode);
    const dispatch = useAppDispatch();

    const handleChangeLanguage = (language : string) => {
        router.push(router.asPath, router.asPath, { locale: language });
    }

    useEffect (
        () => {
        document.body.style.backgroundColor = isDarkmode ? "#292c35" : "#fff";
      }, [isDarkmode]);


    return (
       
        <div >
            <button 
                className={styles.iconContainer}
                onClick={
                    () => {
                        dispatch(toggleDarkmode());
                        console.log(isDarkmode);
                    }
                }
            >
                <Image 
                    src={sunPic}
                    width={20}
                    height={20}
                    alt={'Dark / Light icon'}
                />
            </button>
            
            <div style={{ background: isDarkmode ? "white" : "yellow" }}></div>
        </div>

    )
}

store.ts

import { configureStore } from '@reduxjs/toolkit'

import darkmodeReducer from './slices/darkmodeSlice'


export const store = configureStore({
  reducer: {
    darkmode: darkmodeReducer
  }
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

darkmodeSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import type { RootState } from '../store'

// Define a type for the slice state
interface DarkmodeState {
  isDarkmode: boolean
}

// Define the initial state using that type
const initialState: DarkmodeState = {
  isDarkmode : false
}

export const darkmodeSlice = createSlice({
  name: 'darkmode',
  // `createSlice` will infer the state type from the `initialState` argument
  initialState,
  reducers: {
    toggleDarkmode: (state) => {
      state.isDarkmode = !state.isDarkmode;
      localStorage.setItem("isDarkmode", `${state.isDarkmode}`);
    }
  },
})

export const { toggleDarkmode } = darkmodeSlice.actions
 
export default darkmodeSlice.reducer

Upvotes: 0

Views: 325

Answers (1)

phry
phry

Reputation: 44106

Your selector is wrong.

Your darkmode slice has the shape

{
  isDarkmode : boolean
}

and together with your configureStore call that means that your store state has the shape

{
  darkmode: {
    isDarkmode : boolean
  }
}

So your selector const isDarkmode = useAppSelector((state) => state.darkmode); will always select an object of the shape of the slice - but not the boolean value inside that. And the way you are using it, that will always be interpreted as a "truthy" value.

So do

const isDarkmode = useAppSelector((state) => state.darkmode.isDarkmode);

instead.

Upvotes: 1

Related Questions