WebComponentsを使ってMUI のPopoverを同じページの複数箇所に出したいときの方法

（2年ほど前のメモが残っていたので記事化…）

# 困ったこと
WebComponents内でMUIのPopoverを同じコンポーネント内の複数箇所に出したいとき、[公式ドキュメント](https://mui.com/material-ui/react-popover/)の実装例をそのまま真似してしまうと、複数箇所で同時にPopoverが表示されてしまう

※補足：
- react-to-webcomponentを使って作成したWebComponents内での実装。
- WebComponentsを使わない場合、普通に書いてもちゃんと別々に表示される。

### 環境
React 18.1.0
TypeScript 4.6.4
Material UI(MUI) v5
react-to-webcomponent

# 結論
- それぞれのPopoverに対して個別のkeyとなる文字列を設定する
- useStateで、↑の個別のkeyの選択状態を管理するstateを定義する
- Popoverのopen内に書く条件を、「Popoverを開く＝true」AND「keyの状態を管理するstateがそのPopoverのkeyと一致している」とする

# 実装例
```tsx
const MyComponent: React.FC = () => {
  // Popover表示位置のref
  const firstRef = useRef<HTMLDivElement>(null);
  const secondRef = useRef<HTMLDivElement>(null);

  // Popover表示制御
  const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
  const [popOverKey, setPopOverKey] = useState<string | null>(null);
  const popOverKeys = {
    firstKey: 'first-popover',
    secondKey: 'second-popover',
  };
  const handlePopoverOpen =
    (key: string) => (event: React.MouseEvent<HTMLElement>) => {
      setPopOverKey(key);
      setAnchorEl(event.currentTarget);
    };
  const handlePopoverClose = () => {
    setPopOverKey(null);
    setAnchorEl(null);
  };
  const open = Boolean(anchorEl);

  return (
    <Grid item style={{ flex: 1 }}>
      <Box>
        <Grid item>
          <div ref={firstRef}></div>
          <Typography
            aria-owns={open ? popOverKeys.firstKey : undefined}
            aria-haspopup="true"
            onMouseEnter={handlePopoverOpen(popOverKeys.firstKey)}
            onMouseLeave={handlePopoverClose}>
            ここにマウスをかざしたときにPopover その1を表示したい
          </Typography>
          <Popover
            id={popOverKeys.firstKey}
            open={open && popOverKey == popOverKeys.firstKey}
            anchorEl={anchorEl}
            onClose={handlePopoverClose}
            container={() => {
              return firstRef.current;
            }}
            anchorOrigin={{
              vertical: 'bottom',
              horizontal: 'left',
            }}
            transformOrigin={{
              vertical: 'top',
              horizontal: 'left',
            }}
            disableRestoreFocus
            style={{ pointerEvents: 'none' }}>
            Popover その1
          </Popover>
        </Grid>
      </Box>
      <Grid container justifyContent="flex-end" style={{ display: 'flex' }}>
        <div ref={secondRef}></div>
        <Grid item style={{ minWidth: '85px' }}>
          <Typography
            align="right"
            aria-owns={open ? popOverKeys.secondKey : undefined}
            aria-haspopup="true"
            onMouseEnter={handlePopoverOpen(popOverKeys.secondKey)}
            onMouseLeave={handlePopoverClose}>
            ここにマウスをかざしたときにPopover その2を表示したい
          </Typography>
          <Popover
            id={popOverKeys.secondKey}
            open={open && popOverKey == popOverKeys.secondKey}
            anchorEl={anchorEl}
            onClose={handlePopoverClose}
            container={() => {
              return secondRef.current;
            }}
            anchorOrigin={{
              vertical: 'bottom',
              horizontal: 'left',
            }}
            transformOrigin={{
              vertical: 'top',
              horizontal: 'left',
            }}
            disableRestoreFocus
            style={{ pointerEvents: 'none' }}>
            Popover その2
          </Popover>
        </Grid>
      </Grid>
    </Grid>
  );
};
```