2

hello

I am trying to make a menu toggle, where I have a variable with false as initial value, using react createContext and useContext hook, I set the initial state as true

// useMenu Context
import React, { useContext, useState } from 'react'

export const useToggle = (initialState) => {
  const [isToggled, setToggle] = useState(initialState)
  const toggle = () => setToggle((prevState) => !prevState)
  // return [isToggled, toggle];
  return { isToggled, setToggle, toggle }
}

const initialState = {
  isMenuOpen: true,
  toggle: () => {},
}

export const MenuContext = React.createContext(initialState)

const MenuProvider = ({ children }) => {
  const { isToggled, setToggle, toggle } = useToggle(false)
  const closeMenu = () => setToggle(false)
  return (
    <MenuContext.Provider
      value={{
        isMenuOpen: isToggled,
        toggleMenu: toggle,
        closeMenu,
      }}>
      {children}
    </MenuContext.Provider>
  )
}
export default MenuProvider

export const useMenu = () => {
  return useContext(MenuContext)
}

so If true it will show the Menu if false it will show the Div where there a div

App.js

const { isMenuOpen } = useMenu()

//the providder
<MenuProvider>
  <Header mode={theme} modeFunc={toggleTheme}/>
      {isMenuOpen ? (
         <Menu />
      ) : (
      <Switch>
        <Route path='/writing' component={Writings} />
        <Route path='/meta' component={Meta} />
        <Route path='/contact' component={Contact} />
        <Route path='/project' component={Project} />
        <Route exact path='/' component={Home} />
        <Route path='*' component={NotFound} />
      </Switch>
    )}
  <Footer />{' '}
</MenuProvider>

and when I add an onclick event the NavLink button of the menu to close it it does not work

Menu


const { closeMenu } = useMenu()
// return statement
{paths.map((item, i) => {
  return (
    <MenuItem
      key={i}
      link={item.location}
      svg={item.icon}
      path={item.name}
      command={item.command}
      onClick={closeMenu}
     />
  )
})}

where did I go wrong

4
  • Just to be clear, can you please elaborate on what exactly the <Menu /> is doing right now? Is it "staying open"? Commented Apr 20, 2021 at 3:44
  • @MichaelHoobler it's a component that contains a list I thought I explained in the last piece of code where MenuItem represents a NavLink component
    – Jagarkin
    Commented Apr 20, 2021 at 11:56
  • @Jargarkin, I meant what is the "unintended behavior" as in: what exactly is component currently doing compared to what the component should be doing". Commented Apr 20, 2021 at 11:59
  • 1
    @MichaelHoobler the intented behavior was to hide menu when isMenuOpen false but when change it to false it always stays as true, problem resolved it was the wrong placement of the Provider
    – Jagarkin
    Commented Apr 20, 2021 at 14:31

1 Answer 1

2

Issue

I suspect the issue is in App where you've a useMenu hook outside the MenuProvider used in App. This useMenu hook is using a MenuContext context but in the absence of a provider it instead uses the default initial context value.

const initialState = {
  isMenuOpen: true,
  toggle: () => {},
};

export const MenuContext = React.createContext(initialState);

export const useMenu = () => {
  return useContext(MenuContext)
};

React.createContext

const MyContext = React.createContext(defaultValue);

Creates a Context object. When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider above it in the tree.

The defaultValue argument is only used when a component does not have a matching Provider above it in the tree. This default value can be helpful for testing components in isolation without wrapping them.

Solution

Since I doubt you want to run/provide more than one menu provider I believe the solution is to move MenuProvider out of and wrap App to provide the context you are updating by nested components.

App.jsx

const { isMenuOpen } = useMenu();

...

<>
  <Header mode={theme} modeFunc={toggleTheme}/>
  {isMenuOpen ? (
    <Menu />
  ) : (
    <Switch>
      <Route path='/writing' component={Writings} />
      <Route path='/meta' component={Meta} />
      <Route path='/contact' component={Contact} />
      <Route path='/project' component={Project} />
      <Route exact path='/' component={Home} />
      <Route path='*' component={NotFound} />
    </Switch>
  )}
  <Footer />
</>

index.jsx (?)

import App from './App.jsx';

...

//the provider
<MenuProvider>
  <App />
</MenuProvider>
1
  • it worked, I suspected that MenuProvider and it's placement in the code has to do something with the state freeze, but since it will wrap on the entire component I just let in App.jsx, this was a learning experience, thank you
    – Jagarkin
    Commented Apr 20, 2021 at 12:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.