Home > Software design >  Unable to access exported state variable from custom hook
Unable to access exported state variable from custom hook

Time:08-05

I have a custom hook for light/dark mode using MUI, it exports a state variable which I then pass to MUI's createTheme to tell it what theme to use. However I can't access the state variable outside of my hook, getting undefined when I console.log it. Anyone know what I'm doing wrong? I took this code directly from the MUI documentation.

Hook code:

const useProvideColorTheme = () => {
    const [mode, setMode] = useState<PaletteMode>('light');

    const colorMode = useMemo(
        () => ({
            toggleColorMode: () => {
                setMode((prevMode: PaletteMode) =>
                    prevMode === 'light' ? 'dark' : 'light',
                );
            },
        }),
        [],
    );

    return {
        colorMode,
        mode,
        setMode,
    };
}

in _app.tsx

import { ProvideColorTheme, useColorTheme } from '../lib/hooks/useColorTheme';
import { createTheme, ThemeProvider } from '@mui/material/styles';


const getDesignTokens = (mode) => {...}


function MyApp({ Component, pageProps }) {
  const appTheme = useColorTheme();
  const theme = useMemo(() => createTheme(getDesignTokens(appTheme.mode)), [appTheme.mode]);
  return (
    <hook>
      <hook>
        <hook>
          <ProvideColorTheme>
            <ThemeProvider theme={theme}>
              <hook>
                <hook>
                  <Component {...pageProps} />
                </hook>
              </hook>
            </ThemeProvider>
          </ProvideColorTheme>
        </hook>
      </hook>
    </hook>
  );
}

MUI Versions

"@mui/styles": "^5.8.0"

"@mui/material": "^5.6.4"

React/Next.js Versions

"react": "18.1.0"

"react-dom": "18.1.0"

"next": "12.1.6"

CodePudding user response:

You cant access it inside your file because that app doesn't exist within ProvideColorTheme. Technically useColorTheme before it gets rendered within the app. This is why your MyApp component needs to live within it.

I would recommend making a CustomProviders file which wrap your app. Something like I have below will work.

const AppProviders = () => {
   return (
      <ProvideColorTheme>
          <MyApp />
      </ProvideColorTheme>
   )
}

function MyApp({ Component, pageProps }) {
  const appTheme = useColorTheme();
  const theme = useMemo(() => createTheme(getDesignTokens(appTheme.mode)), [appTheme.mode]);
  return (
     <ThemeProvider theme={theme}>
        <Component {...pageProps} />
     </ThemeProvider>
  );
}

This is the issue with providers and you will often get put into 'Provider Hell' where you have dozens of providers that all need each other.

  • Related