skip to Main Content

I have a custom dropdown that is triggered by a button. If it is expanded, then isExpanded===true. To close it, I use useEffect, which adds a click handler to the entire document only if isExpanded is true.
The problem: the click handler is triggered as soon as I click on the button even before it is assigned, and therefore the dropdown content immediately disappears (does not appear on the page).
It feels like document.addEventListener is assigned before useEffect fires.

const [isExpanded, setIsExpanded] = useState(false);

useEffect(() => {
  if (!isExpanded) {
    return;
  }

  const handleDocumentClick = () => {
    setIsExpanded(false);
  };

  document.addEventListener('click', handleDocumentClick);

  return () => {
    document.removeEventListener('click', handleDocumentClick);
  };
}, [isExpanded]);

<button
  type="button"
  onClick={setIsExpanded(current => !current)}
  >
  Sort by:
</button>

<div
  style={{ display: isExpanded ? 'block' : 'none' }}
>
  Some content
</div>

I’ve tried moving the logic from useEffect directly to the button handler, but the document.addEventListener still fires before it’s assigned.

2

Answers


  1. You can stop the event propagation in the button click handler.

    <button
        type="button"
        onClick={e => {
            e.stopPropagation();
            setIsExpanded(current => !current);
        }}>
        Sort by:
    </button>
    
    Login or Signup to reply.
  2. Modify your button’s click handler to accept the event parameter and call event.stopPropagation() to prevent the event from propagating further:

    <button
      type="button"
      onClick={(event) => {
        event.stopPropagation();
        setIsExpanded((current) => !current);
      }}
    >
      Sort by:
    </button>
    

    By stopping the event propagation, the document-level click event won’t be triggered immediately after clicking the button, allowing the dropdown content to appear correctly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search