Issue
You are using a single boolean state to toggle the visibility of all the dropdowns.
const {
ref,
isComponentVisible,
setIsComponentVisible
} = useComponentVisible(false); // <-- single state
const toggle = () => {
setIsComponentVisible((prevState) => !prevState); // <-- toggle all
};
...
<DropdownMenu
show={isComponentVisible} // <-- all toggled
ref={ref}
>
{value.name}
</DropdownMenu>
Solution
Initialize the state to hold an object of boolean values and use the state updater to toggle a specific one by id.
const Form = () => {
const {
ref,
isComponentVisible,
setIsComponentVisible
} = useComponentVisible(
// Map the products to object of id:boolean pairs
products.reduce(
(visible, { id }) => ({
...visible,
[id]: false
}),
{}
)
);
const toggle = (id) => {
// shallow copy state and toggle the specific id's visibility value
setIsComponentVisible((visible) => ({
...visible,
[id]: !visible[id]
}));
};
return (
<div>
{products.map((value) => (
<div key={value.id}>
<DropdownMenu
show={isComponentVisible[value.id]} // set visible by id
ref={ref}
>
{value.name}
</DropdownMenu>
<div style={{ paddingBottom: "100px" }}>
<div key={value.id}>{value.name}</div>
<button type="button" onClick={() => toggle(value.id)}>
Open
</button>
</div>
</div>
))}
</div>
);
};

If you want to only toggle a single dropdown at a time, use a single nullable state to hold the id of the dropdown you want open.
const Form = () => {
const {
ref,
isComponentVisible,
setIsComponentVisible
} = useComponentVisible(null); // <-- null == none open
const toggle = (id) => {
// toggle back to null or set new id
setIsComponentVisible((visible) => (visible === id ? null : id));
};
return (
<div>
{products.map((value) => (
<div key={value.id}>
<DropdownMenu
show={isComponentVisible === value.id} // <-- check if id matches
ref={ref}
>
{value.name}
</DropdownMenu>
<div style={{ paddingBottom: "100px" }}>
<div key={value.id}>{value.name}</div>
<button type="button" onClick={() => toggle(value.id)}>
Open
</button>
</div>
</div>
))}
</div>
);
};
