react-contexify
react-contexify copied to clipboard
Dynamically generate Items for Menu
Do you want to request a feature or report a bug? This may be a feature request, or I may simply be missing something. What is the current behavior? Currently, you have to explicitly define the specific Items to render as JSX components. I'm attempting to get the passed props in a component so I can render a dynamic list.
To clarify, I am trying to use this in MySeparateComponent:
const { show } = useContextMenu({
id: 'my-separate-component'
});
//...
const onContextClick = (ev) => {
show(ev, {
items: [itemA, itemB, itemC,]
})
}
And then I want to access the items
array in the context menu to generate the list of Items:
function MyCustomContextMenu(props) {
const handleItemClick = (itemClicked) => {
//... (Do something with the item that was passed from props)
}
return (
<Menu
id="my-separate-component"
>
{props.items.map(( item, index ) => <Item onClick={() => handleItemClick(item)} key={index}>{item.name}</Item>)}
</Menu>
}
Am I missing something? Or is this outside the scope of this library?
The props are passed to the onClick. I solved this w mobx by having MyCustomContextMenu fetch items from observable state.
Hmm... interesting. I use a combination of redux and context (redux handles app data, context is for passing derived data (from expensive calculations)).
I'll look into creating a context for this. Thanks for your help @eirikhm!!
EDIT: I'll close this issue after I've had some time to build and test.
@Xuroth can you post your final solution. I face the same problem.
thx
Yeah. This feature is exactly what we need ❤️
I solved using a React.Children because the limitation of use ReactFragment
That's the code:
ContextMenu
import { useMemo } from 'react';
import { Menu, Item, Separator, Submenu, ItemParams } from 'react-contexify';
import 'react-contexify/dist/ReactContexify.css';
export type ContextMenuItem = {
label: string;
subMenuItems?: ContextMenuItem[];
hasSubmenu?: boolean;
disabled?: boolean;
handleItemClick: (args: ItemParams<any, any>) => void;
};
type Props = {
menuId: string;
items: ContextMenuItem[];
};
export default function ContextMenu({ menuId, items }: Props) {
const children = useMemo(() => {
const elements: React.ReactNode[] = [];
for (let index = 0; index < items.length; index++) {
const item = items[index];
elements.push(
<Item
key={item.label}
onClick={item.handleItemClick}
disabled={item.disabled}
>
{item.label}
</Item>,
);
if (index !== items.length - 1) elements.push(<Separator />);
if (item.hasSubmenu)
elements.push(
<Submenu label={item.label}>
{item.subMenuItems?.map((subMenuItem) => (
<Item
key={subMenuItem.label}
onClick={subMenuItem.handleItemClick}
disabled={subMenuItem.disabled}
>
{subMenuItem.label}
</Item>
))}
</Submenu>,
);
}
return elements;
}, []);
return <Menu id={menuId}>{children}</Menu>;
}