Closed1
React で Vue の slot っぽいやつの実装
import type { FC, ReactElement, ReactNode } from 'react';
type Props = {
children: ReactElement[] | ReactElement | undefined;
};
type SlotProps = { children: ReactNode };
type SlotComponent = FC<SlotProps>;
const HeaderSlot: SlotComponent = () => null;
const BodySlot: SlotComponent = () => null;
const FooterSlot: SlotComponent = () => null;
type Slot = ReactElement<SlotProps>;
const _Layout: FC<Props> = ({ children }) => {
const getSlot = (
_children: Slot[] | Slot | undefined,
slot: SlotComponent,
): ReactNode => {
if (Array.isArray(_children))
return _children.find((child) => child.type === slot)?.props.children;
if (_children?.type === slot) return _children.props.children;
return undefined;
};
const header = getSlot(children, HeaderSlot);
const body = getSlot(children, BodySlot);
const footer = getSlot(children, FooterSlot);
return (
<div>
<header>{header}</header>
<div>{body}</div>
<footer>{footer}</footer>
</div>
);
};
export const Layout = Object.assign(_Layout, {
Header: HeaderSlot,
Body: BodySlot,
Footer: FooterSlot,
});
const Example = () => (
<Layout>
<Layout.Header>Header</Layout.Header>
<Layout.Body>Body</Layout.Body>
<Layout.Footer>Footer</Layout.Footer>
</Layout>
);
/*
<div>
<header>Header</header>
<div>Body</div>
<footer>Footer</footer>
</div>
*/
このスクラップは2022/08/07にクローズされました