cf.completefrontend

Predict the outputMedium

A click inside a portal: which handlers run, and in what order?

The row listens to clicks twice: with React's onClick, and with a DOM listener added with addEventListener. Its Details button opens a dialog rendered through a portal into document.body.

What does it log, and what does the page show?
import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
 
export default function App() {
  const [open, setOpen] = useState(false);
  const rowRef = useRef(null);
 
  useEffect(() => {
    const row = rowRef.current;
    const listener = () => console.log("row: DOM listener");
    row.addEventListener("click", listener);
    return () => row.removeEventListener("click", listener);
  }, []);
 
  return (
    <div ref={rowRef} onClick={() => console.log("row: onClick")}>
      <button
        onClick={() => {
          console.log("Details clicked");
          setOpen(true);
        }}
      >
        Details
      </button>
      {open &&
        createPortal(
          <div role="dialog" aria-label="Order details">
            <button
              onClick={() => {
                console.log("Close clicked");
                setOpen(false);
              }}
            >
              Close
            </button>
          </div>,
          document.body,
        )}
    </div>
  );
}

It runs in development, rendered as <App />, and then:

  1. You click Details.
  2. You click Close in the dialog.

The answer

Work out every line it logs, in order, and what the page shows at the end. Then check.

Checking your sign-in…