I need to be able to detect when the Flowbite Dropdown opens and closes from its parent component. When opened, I need to call an API endpoint and update the state of one of its items, but only when opened. The reason for this is I have dozen's of these dropdowns present on the page at once and running these update functions all at once is detrimental to the performance.
Here's a minimal example component. Populate would be an async call to the backend. This works, and does what I want, but this runs for every item for every RowOptions
component rendered on the screen. This is a lot of processing. I want this to happen lazily only for the items in the open dropdown.
export default function RowOptions() {
return (
<>
<Dropdown label={<div><DotsIcon/></div>}>
<Dropdown.Header>Actions</Dropdown.Header>
{items.map(item => (
<Dropdown.Item>{populate()}</Dropdown.Item>
))}
</Dropdown>
</>
)
}
I'd hoped it would have an onOpen
or onClose
property I could hook to, but it does not. Is there a wrapper I can use to get this functionality? I tried using a ref to track when it's visible, but that only worked partially.
For example, I added a div within the dropdown with a ref <div ref={myRef}><div>
and then connected that to the state within the dropdown label's onClick:
export default function RowOptions() { const [isOpen, setIsOpen] = useState(false); const myRef = useRef(null);
return ( <> <Dropdown label={<div onClick={() => { setIsOpen(myRef === null) }}><DotsIcon/></div>}> <div ref={myRef}><div> <Dropdown.Header>Actions</Dropdown.Header> {items.map(item => ( <Dropdown.Item>{populate()}</Dropdown.Item> ))} </Dropdown> </> ) }
This worked partially. I could essentially track the state changing if the button was clicked...but this fall apart as soon as you clicked an item or out of the dropdown. Then the state would get all messy. So this approach clearly wasn't the best option.
My last thought was using a Mutation observer, hooking up to the Dropdown, and then watching the updating of the classes. I'm not sure if this is the best approach, specifically for React, but that's what I'm working on now.