I am trying to hide multiple divs with useSate.
They will be rendered random on the page, not from a list.
I have managed to do so by setting up different variables but couldn't find a more generic solution: https://stackblitz.com/edit/react-t3shrc?file=src/App.js
Also is there a way to close them when clicking outside?
Can you help please.
export default function App() {
const [isVisible, setIsVisible] = useState(false);
const [isVisible2, setIsVisible2] = useState(false);
const showInfo = (e, setIsVisible) => {
e.preventDefault();
setIsVisible(true);
};
const hideInfo = (e, setIsVisible) => {
e.preventDefault();
setIsVisible(false);
};
return (
<div>
<button
onClick={(e) => {
showInfo(e, setIsVisible);
}}
>
Show info 1
</button>
{isVisible && (
<div className="info">
Info 1
<button
onClick={(e) => {
hideInfo(e, setIsVisible);
}}
>
Close
</button>
</div>
)}
<br></br>
<br></br>
<button
onClick={(e) => {
showInfo(e, setIsVisible2);
}}
>
Show info 2
</button>
{isVisible2 && (
<div className="info">
Info 2
<button
onClick={(e) => {
hideInfo(e, setIsVisible2);
}}
>
Close
</button>
</div>
)}
</div>
);
}
CodePudding user response:
I'm not 100% sure what you mean by a more 'generic' solution. Here is what comes to my mind:
First of all, we create a more complex object to basically hold all the variables / sections we encounter and use this as our state.
const initialVisibleAreas = {
area1: true,
area2: false
};
const [visibleAreas, setVisibleAreas] = useState(initialVisibleAreas);
Please note that this is propabably something you want to generate from your data using Object.keys(...) or mapping an array.
Next up, we create the functions for the buttons to use this new state accordingly:
// shows the element by given key
const showInfo = (event, key) => {
event.preventDefault();
setVisibleAreas({ ...visibleAreas, ...{ [key]: true } });
};
// hides the element by given key
const hideInfo = (event, key) => {
event.preventDefault();
setVisibleAreas({ ...visibleAreas, ...{ [key]: false } });
};
// sets every key to false to hide them all at once
const hideAllInfo = (event) => {
event.preventDefault();
const allFalse = Object.assign(
...Object.keys(visibleAreas).map((key) => ({ [key]: false }))
);
setVisibleAreas(allFalse);
};
Last but not least, we use them in jsx. This is basically one 'section':
<button
onClick={(e) => {
showInfo(e, 'area2');
}}
>
Show info 2
</button>
{
visibleAreas['area2'] && (
<div className="info">
Info 2
<button
onClick={(e) => {
hideInfo(e, 'area2');
}}
>
Close
</button>
</div>
);
}
To answer the last question; nothing is holding you to call 'hideAllInfo' inside a onClick handler of your surounding div. Sample is included in the modified stackblitz.
Have a complete look at the modified stackblitz
EDIT: In the case you want to close all areas by clicking the surrounding div, make sure to not propagate the button click event with:
event.stopPropagation();
I updated the stackblitz once again.