Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

'dispatch' is not defined when using useReducer with useContext in react

I’m trying to figure out how to change global state from a componenet using useContext and useReducer dispatch method.

The component is simply should change the backgournd of the page on a click

Here is how I defined the context ThemeContext.js

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import { createContext, useReducer } from "react";
import ThemeReducer from './ThemeReducer'

const INITIAL_STATE = {
    isLightTheme: true,
    light: {syntax: '#555', ui: '#ddd', bg: '#eee'},
    dark: {syntax: '#ddd', ui: '#333', bg: '#555'},
}

export const ThemeContext = createContext(INITIAL_STATE);

const ThemeContextProvider = ({ children }) => {
   const [state, dispatch] = useReducer(ThemeReducer, INITIAL_STATE);
    return ( 
        <ThemeContext.Provider value={{
            isLightTheme: state.isLightTheme,
            light: state.light,
            dark:  state.dark,
            dispatch,
        }}>
            {children}
        </ThemeContext.Provider>
     );
}     
export default ThemeContextProvider;

The ThemeReducer.js is:

const ThemeReducer = (state, action) => {
    switch (action.type) {
      case "SET_DARK":
        return {
            isLightTheme: false,
        };    
      case "SET_LIGHT":
            return {
                isLightTheme: true,
            }; 
      default:
        return state;
    }
  };  
  export default ThemeReducer;

app.js:

function App() {
  return (
    <div className="App">
       <ThemeContextProvider>        
          <Navbar />
          <BookList />
          <ThemeToggle />
       </ThemeContextProvider>
    </div>
  );
}

export default App;

And the ThemeToggle.js compoenent

const ThemeToggle = () => {

    return ( 
        <button onClick={()=>dispatch({type: "SET_DARK"})}>Change theme</button>
     );
}
 
export default ThemeToggle;

However I get this error:

src/components/ThemeToggle.jsx
  Line 6:30:  'dispatch' is not defined 

I don’t understand why. Because dispatch is supposed to be in the context. I’m wondering what is wrong here and how can I fix it?

P.S BooKList compoenent.

import  { useContext } from 'react'
import { ThemeContext } from '../context/ThemeContext';


const BookList = () => {
    const {isLightTheme, light, dark} = useContext(ThemeContext)
    const theme = isLightTheme ? light : dark;
    return ( 
        <div  style={{background : theme.ui , color: theme.syntax}}>
            <ul>
                <li stryle={{background: theme.ui}} >The way of kings</li>
                <li stryle={{background: theme.ui}} >The namoe fot the wind</li>
                <li stryle={{background: theme.ui}} >The Final empire</li>
            </ul>
        </div>
     );
}

>Solution :

It appears you are missing accessing the ThemeContext in ThemeToggle. Use the useContext hook to access the ThemeContext Context value and destructure the dispatch function.

const ThemeToggle = () => {
  const { dispatch } = useContext(ThemeContext);
  return ( 
    <button onClick={() => dispatch({type: "SET_DARK"})}>
      Change theme
    </button>
  );
}
 
export default ThemeToggle;

And for completeness’ sake, add dispatch to the default context value.

const INITIAL_STATE = {
  isLightTheme: true,
  light: {syntax: '#555', ui: '#ddd', bg: '#eee'},
  dark: {syntax: '#ddd', ui: '#333', bg: '#555'},
  dispatch: () => {},
}

export const ThemeContext = createContext(INITIAL_STATE);

The ThemeReducer reducer function is stripping out state in the set light/dark cases. You need to preserve the existing state.

const ThemeReducer = (state, action) => {
  switch (action.type) {
    case "SET_DARK":
      return {
        ...state,
        isLightTheme: false,
      };
  
    case "SET_LIGHT":
      return {
        ...state,
        isLightTheme: true,
      };

    default:
      return state;
  }
};  
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading