function Nav(){
const [toggleDropDownAbout, setToggleDropDownAbout] = useState(fasle);
const [toggleDropDownCareers, setToggleDropDownCareers] = useState(fasle);
const [toggleDropDownNew, setToggleDropDownNew] = useState(fasle);
return(
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>About Us <FaCaretDown className='rotate'/></Link>
{toggleDropDownAbout &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Careers <FaCaretDown className='rotate'/></Link>
{toggleDropDownCareers &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Whats new <FaCaretDown className='rotate'/></Link>
{toggleDropDownNew &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
)
}
It's running but is there a way to use one useState or some other way to get the same result. I just dont think this code is good and i dont have any idea how to do this in other way
CodePudding user response:
useState
allows you to declare an object as a value too. You can leverage that to define a single state.
function Nav(){
const [toggleStates, setToggleStates] = useState({
toggleDropDownAbout,
toggleDropDownCareers,
toggleDropDownNew
});
return(
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>About Us <FaCaretDown className='rotate'/></Link>
{toggleStates.toggleDropDownAbout &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Careers <FaCaretDown className='rotate'/></Link>
{toggleStates.toggleDropDownCareers &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Whats new <FaCaretDown className='rotate'/></Link>
{toggleStates.toggleDropDownNew &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
)
}
However when using the above approach you need to be mindful that updates using setToggleStates
will overwrite the entire state value and not merge it. So you should spread and update the object like
setToggleState(prev => ({
...prev,
toggleDropDownAbout: !prev.toggleDropDownAbout
}));
P.S. There is nothing wrong with keeping multiple states with useState
in your component. Ideally, you should consider creating a single state with a value as object if the states are related and belong to a single property
Also depending on interaction, you can simplify the above code. In case your intention is to only open one dropdown at a time, you can store the id enum of the dropdown as state value and use it.
function Nav(){
const [toggleState, setToggleState] = useState(null);
return(
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>About Us <FaCaretDown className='rotate'/></Link>
{toggleState === 'about' &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Careers <FaCaretDown className='rotate'/></Link>
{toggleState === 'careers' &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
<Link to='/' className='flex items-center text-slate-500 font-medium text-base px-3 py-3 nav-item hover:text-red-700 relative gap-1 '>Whats new <FaCaretDown className='rotate'/></Link>
{toggleState === 'new' &&
<ul className='grid pl-6 dropdown-item bg-red-100 lg:absolute top-12 z-10'>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>History</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Quality Policy</Link>
<Link to='/' className='text-slate-500 hover:text-red-700 text-base'>Vision / Mission</Link>
</ul>
}
)
}
and update using
const toggleDropdown = (id) => {
setToggleState(prev=> {
if(prev === id) {
// close the opened dropdown
return null;
}
return id;
})
}
CodePudding user response:
Just to add to Shubham Khatri's answer, after writing
const [toggleStates, setToggleStates] = useState({
toggleDropDownAbout,
toggleDropDownCareers,
toggleDropDownNew
});
you can destructure them to use them to avoid toggleStates.XX
like so
const {toggleDropDownAbout, toggleDropDownCareers, toggleDropDownNew} = toggleStates;