Issue
This Content is from Stack Overflow. Question asked by Mintee
I’m using NextUI Popover component and I want to manually close the Popover with a cancel button. I can open and close it with isOpen
prop but the main problem is that I have it in a map loop, when I open one all the other opens. How can I solve this?
Popover JSX
<Popover placement="top">
<Popover.Trigger>
<Button auto light>
<DeleteDocumentIcon
fill="#F31260"
className="cursor-pointer"
width={26}
height={26}
/>
</Button>
</Popover.Trigger>
<Popover.Content>
<DeleteUser
snip={snip}
handleDelete={handleDelete}
/>
</Popover.Content>
</Popover>
Overlay buttons
<Grid>
<Button size="sm" light>
Cancel
</Button>
</Grid>
<Grid>
<Button
size="sm"
shadow
color="error"
onClick={() => handleDelete(user.id)}
>
Delete
</Button>
</Grid>
Solution
Okay, so the problem is that you’re using a binary state (isOpen
) to represent something with more than binary state– namely, the isOpen
state of every snip.
There are a few ways to do this, but I personally like having the state be an object containing a mapping from index => boolean
const [allOpenStates, setAllOpenStates] = useState({});
// in this case, we'll have an object that maps from an
// index to a boolean
// the default state is closed, so a missing value in the map
// will get interpreted as false
{snipsData.map((snip, index) => (
<div key={index} className="hoverable-item flex gap-2">
//....
<Popover placement="top"
isOpen={allOpenStates[index]} // it will be undefined if it hasn't ever been opened, which is fine, since undefined is falsey
onOpenChange={nowOpen => setAllOpenStates(oldState => {...oldState, [index]: nowOpen} )}>
//Pop.Trigger Button sets allOpenStates[index] = true
<Popover.Trigger>
<Button auto light>
<DeleteDocumentIcon
fill="#F31260"
className="cursor-pointer"
width={26}
height={26}
/>
</Button>
</Popover.Trigger>
<Popover.Content>
<DeleteUser
snip={snip}
handleDelete={handleDelete}
setIsOpen={setIsOpen}
/>
</Popover.Content>
</Popover>
</div>
))}
I’m doing this without trying it myself, so some of the syntax may be off. But the general idea is that you need to keep track of the open state for each index, and use that individual index’s state for determining if the popover is open and how to handle open/close events.
Another solution would be using a Set of numbers (the index values), where Set membership indicates that the popover is open. Opening the popover would add that index to the set, and closing would remove from the set.This would require some ugly code though, since set operations are mutating.
This Question was asked in StackOverflow by Mintee and Answered by Nathan It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.