Reputation: 620
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
Upvotes: 2
Views: 994
Reputation: 202605
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)
};
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.
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>
Upvotes: 2