我正在尝试编写一个包装器组件来决定是否拥有 ListItem渲染一个react-router-dom链接
或一个按钮
// inside some component
let props
if ("uri" in navItem) {
props = { component: Link, to: navItem.uri }
} else {
props = { button: true, onClick: navItem.onClick }
}
return (
<ListItem {...props}>
...some more code ...
</ListItem
)
它在 ListItem
上提示说没有重载与此调用匹配。我猜这个错误是因为没有输入 props
变量。但是,我无法理解如何输入这个,对于我的 TS 水平来说太复杂了。
我可以获得一些有关如何输入这些内容的说明吗?
编辑:
为了添加更多信息,我只是想将其干燥:
export type NavItem = Omit<BaseNavItem, 'onClick'> | Omit<BaseNavItem, 'uri'>;
type BaseNavItem = {
icon: React.ReactNode;
label: string;
uri: string;
onClick: () => void;
};
// MyComponent.tsx
// it will render Link or buttons depending
// on whether uri or onClick was passed in the navItem
if ("uri" in navItem) {
return (
<li>
<ListItem key={label} component={RouterLink} to={navItem.uri}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
</li>
)
} else {
return (
<ListItem key={label} button onClick={navItem.onClick}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
)
}
最佳答案
这是一个简单的解决方案:
import React from "react";
import { ListItem, ListItemIcon, ListItemText } from "@material-ui/core";
import { Link } from "react-router-dom";
interface INavItem {
icon: React.ReactNode;
label: string;
// ? makes the prop optional
// it can be undefined
uri?: string;
onClick?: () => void;
}
interface Props {
navItem: INavItem;
}
function NavItem({ navItem }: Props) {
const Inner = (
<>
<ListItemIcon>{navItem.icon}</ListItemIcon>
<ListItemText primary={navItem.label} />
</>
);
if (navItem.uri) {
return (
<ListItem component={Link} to={navItem.uri}>
{Inner}
</ListItem>
);
}
return (
<ListItem button onClick={navItem.onClick}>
{Inner}
</ListItem>
);
}
export default NavItem;
至于根据 component
prop 定义 props
,它要复杂得多,在这种情况下是不必要的。
检查文档:https://material-ui.com/guides/typescript/#usage-of-component-prop
示例:
import React, { ElementType } from "react";
import {
ListItem,
ListItemIcon,
ListItemText,
ListItemProps,
} from "@material-ui/core";
import { Link } from "react-router-dom";
import { People, Edit } from "@material-ui/icons";
interface INavItem {
icon: React.ReactNode;
label: string;
}
export type MyListItemProps<C extends ElementType> = ListItemProps<
C,
{ component?: C }
> &
INavItem;
function NavItem<C extends ElementType>({
icon,
label,
...props
}: MyListItemProps<C>) {
return (
<ListItem {...props}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
}
const navItems = [
{ to: "/users", icon: People, label: "Users" },
{ icon: Edit, label: "Edit", onClick: () => {} },
];
// Usage
const Nav = () => {
return navItems.map(({ to, icon, label, onClick }) => {
if (to) {
return <NavItem<Link> to={to} icon={icon} label={label} />;
}
return <NavItem icon={icon} label={label} button onClick={onClick} />;
});
};
export default Nav;
或
const navItems = [
{ to: "/users", icon: People, label: "Users" },
{ icon: Edit, label: "Edit", onClick: () => {}, button: true },
];
// Usage
const Nav = () => {
return navItems.map(({ to, ...props }) => {
if (to) {
return <NavItem<Link> to={to} {...props} />;
}
return <NavItem {...props} />;
});
};
export default Nav;
关于reactjs - 如何为 Material UI ListItem 输入 props?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62987470/