The issue in first demo is the handleClickOutside triggers no matter where you clicked. When you click on the About button, it makes handleAboutMenuActive function trigger twice.
In my opinion the better way to implement this effect is to check where the user clicked. We can use useRef.
First, add a ref for the button in App.js and pass it as a prop to it's child component Dropdown:
import React, { useState, useRef } from 'react';
// some other code
export default function App() {
const buttonRef = useRef();
// some other code
return (
<div>
<button ref={buttonRef} onClick={handleAboutMenuActive}>About</button>
{aboutMenuActive && (
<Dropdown
buttonRef={buttonRef}
onClickOutside={() => {
handleAboutMenuActive();
}}
></Dropdown>
)}
</div>
)
}
Second, add another ref for the whole ul element and check both ref whenever the handleClickOutside is triggered.
import React, { useEffect, useRef } from 'react';
export default function Dropdown({ buttonRef, onClickOutside }) {
const listRef = useRef()
useEffect(() => {
function handleClickOutside(event) {
// refs will exist after the elements are rendered.
// this condition prevents the refs were still undefined.
if (!listRef.current || !buttonRef.current) {
return;
}
// check if user clicked on the button
if (buttonRef.current.contains(event.target)) {
return;
}
// check if user clicked on the list
if (listRef.current.contains(event.target)) {
return;
}
onClickOutside();
}
// some other code
})
return (
<ul ref={listRef}>
<li>Company</li>
<li>Contact</li>
</ul>
);
}