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

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Jagarkin
  • 468
  • 1
  • 5
  • 14
  • Just to be clear, can you please elaborate on what exactly the `` is doing right now? Is it "staying open"? – Michael Hoobler Apr 20 '21 at 03: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 Apr 20 '21 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*". – Michael Hoobler Apr 20 '21 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 Apr 20 '21 at 14:31

1 Answers1

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>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 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 Apr 20 '21 at 12:07