alex-cory/react-useportal

Conditional rendered elements fire as outside click events

Closed this issue · 6 comments

Came across an issue when conditionally rendering elements within a portal. Buttons render and work properly if used individually but when conditionally rendered the onClick events close the portal since 'outside' click events. Setting the closeOnOutsideClick: false works fine as a temporary fix but was curious if there was a known solution. Also tried binding e.stopPropagation() in onClick events.

AddTaskCard.js

{isOpen && (
  <>
    <Portal>
      <div className="pointer-events-none fixed w-full h-full top-0 left-0 flex items-center justify-center">
        <div className="modal-overlay absolute w-full h-full bg-gray-800 opacity-50"></div>
      </div>
    </Portal>
    <Portal>
      <AddTaskModal close={closePortal} items={dropItems} />
    </Portal>
  </>
)}

AddTaskModal.js

const [viewAll, setViewAll] = useState(false);

const viewAllItems = () => {
  setViewSize(items.length);
  setViewAll(!viewAll);
};
const resetView = () => {
  setViewSize(3);
  setViewAll(!viewAll);
};
...
<div className="flex justify-end p-3 items-center">
  {/* does not work */}
  {viewAll ? (
    <ResetViewButton onClick={resetView} />
  ) : (
    <ViewAllButton onClick={viewAllItems} />
  )}
  {/* works */}
  <ResetViewButton onClick={resetView} />
  {/* also works */}
  <ViewAllButton onClick={viewAllItems} />
</div>

Could you make a codesandbox with a repro of this bug please :)

Finally got time to look at this today. There seems to be some sort of race condition. What I think is happening is react's state is updating the dom before the document.addEventListener('click', handleOutsideClick) fires. Because of this, the element is removed from the dom before we check if portal.current.contains(clickedElement). Since the clickedElement is no longer in the dom, it shows it is not a child of the portal. Hm...

I think I figured it out. Instead of document.addEventListener('click', handleOutsideClick) we need document.addEventListener('mousedown', handleOutsideClick). Check it https://codesandbox.io/s/stupefied-kalam-wwkl3

Update your sandbox to v1.0.2 of react-useportal it should work

Closing, feel free to reopen if it didn't fix the problem