0

I want to change with a toggle in navbar which theme the app will apply, I can update normally the context with the consumer and provider of defaultTheme, but my app didn't update this information.

I've console logged some components to see if they're receiving my context updates, and all is normal, but in my App.tsx, the context only send the first state, and all updates isn't received by it

context.js

const Context = createContext({
  defaultTheme: dark,
  toggleTheme: () => {},
});

export function ThemeContextProvider({ children }) {
  const [theme, setTheme] = useState(dark);

  function toggleTheme() {
    setTheme(theme === dark ? light : dark);
  }
  
  return (
    <Context.Provider value={{ defaultTheme: theme, toggleTheme }}>
    {children}
    </Context.Provider>
  )
}

export function useTheme() {
  const theme = useContext(Context)

  return theme;
}

App.tsx

function App() {
  const { defaultTheme } = useTheme();

  return (
    <ThemeContextProvider>
      {defaultTheme.title === 'dark' ? (
        <ThemeProvider theme={dark}>
          <GlobalStyle />
          <Routes />
        </ThemeProvider>
      ) : (
        <ThemeProvider theme={light}>
          <GlobalStyle />
          <Routes />
        </ThemeProvider>
        ) }
    </ThemeContextProvider>

  );
}

Navbar.tsx

 const { colors } = useContext(ThemeContext);
  const { defaultTheme, toggleTheme } = useTheme();

  return (
    <div id='navbar'>
      <div className='navbar-container'>

          <div className='theme-switcher'>
            { defaultTheme.title === 'dark' ? <RiMoonClearFill /> : <RiMoonClearLine />}
            <Switch
              onChange={toggleTheme}
              checked={defaultTheme.title === 'light'}
              checkedIcon={true}
              uncheckedIcon={false}
              height={10}
              width={40}
              handleDiameter={20}
              offHandleColor={colors.main}
              onHandleColor={colors.text}
              offColor={colors.background}
              onColor={colors.main}
            />
            { defaultTheme.title === 'light' ? <FaSun /> : <FaRegSun />}
          </div>
...
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
pedroflp
  • 15
  • 2

1 Answers1

0

App.tsx is not wrapped within ThemeContextProvider so you cant access that context value inside App.tsx. Its context value is only accessible to children components where ThemeContextProvider is wrapped around.

So i suggest you to move this whole chunk to a new component and call useTheme() inside that child component.

<ThemeProvider theme={defaultTheme.title === 'dark' ? dark : light}>
  <GlobalStyle />
  <Routes />
</ThemeProvider>

And i have made changes to your conditional rendering to make to more compact and readable.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92