我正在使用MaterialUI的ButtonGroup作为下拉菜单,并且有一个模式问题,试图创建一系列的CTA,我可以很容易地在其中交换;其中所有的组件都是可重用的,并且下拉菜单中的选择是动态的,也就是说。
const CTAs = [
<Foo {...foo} />, // these look like <MenuItem>{blah}</MenuItem>
<Bar {...bar} />,
<Baz {...baz} />,
];
return (
<DropDown>
{CTAs}
</DropDown>
);
// DropDown looks something like this
const [open, setOpen] = React.useState<boolean>(false);
const anchorRef = React.useRef<HTMLDivElement>(null);
return (
<Grid container direction="column" alignItems="center">
<Grid item xs={12}>
<ButtonGroup variant="contained" ref={anchorRef}>
<Button
variant="contained"
onClick={toggleOpen}
>
{label}
</Button>
</ButtonGroup>
<ListWrapper
anchorEl={anchorRef.current}
open={open}
setOpen={setOpen}
> {/* Popper > Grow > Paper > ClickAwayListener > MenuList > children */}
{children}
</ListWrapper>
</Grid>
</Grid>
);
然而,当这些CTA中的一些需要模态确认时,我遇到了问题,因为模态会在下拉式中断裂;下拉式捕获文本输入,关闭下拉式会破坏模态。
我怎么做呢?
我试过的。
我通过添加一个函数来解决这个问题,该函数返回两个节点,而不是只有一个节点。
interface CTAState {
open: boolean;
// and other stuff that used to be inside the CTAs
}
const GetFoo = (props): [React.ReactNode, React.ReactNode] => {
const [state, setState] = React.useState<CTAState>({ open: false });
const setOpen = (val: boolean): void => setState((prevState) => ({
...prevState,
open: val,
}));
const onSend = (): void => {
// do cool stuff which used to be in <Foo /> click
setOpen(false);
};
return [
(<Foo {...props} onClick={() => setOpen(true)} />),
(<Dialog open={state.open} onSend={onSend} />),
];
};
// ..
const CTAs = [GetFoo(foo), GetBar(bar), GetBaz(baz)];
return (
<DropDown>
{CTAs.map(([button]) => button)}
</DropDown>
{CTAs.map(([, dialog]) => dialog)}
);
这似乎是一个反模式,因为我不得不使用一些不是Component的东西,用一个react钩子来处理状态,复杂性不断增加,而且变得很难跟踪CTA本身发生了什么。
有什么方法可以做到这一点?
如果我的理解是正确的,模式确认会关闭下拉菜单,对吗?如果是这样,请尝试以下方法。
// ...
<ListWrapper
anchorEl={anchorRef.current}
open={open}
setOpen={(event) => {
event.preventDefault()
setOpen(event)
}}
> {/* Popper > Grow > Paper > ClickAwayListener > MenuList > children */}
{children}
</ListWrapper>
// ...