We all know, we can use props to implement component slots. This is a good way, but the props of the components will become more and more.
Also, you can filter the children by element's type, but it isn't a good idea.
And, you can use HOC to wrap the Component, and use Proxy to reduce the children. you can use the subComponent, like:
<YouComponent.SubComponentA>a</YouComponent.SubComponentA>
And then, your Component's props will get:
slot: {
SubComponentA: {children, props}
}
This is a good idea. But There is a better way.
We focus on children, children will be a array, or string, or a ReactElement, or undefined.
The ReactElement has type, you can check the child with the type's name.
You will use your Component like this:
<YouComponent>
<Slot name="SubComponentA">a</Slot>
b
</YouComponent>
<Slot />
is a component that it render null. And it has a generator function, like this:
import {ReactElement} from 'react'
import {SlotProps} from './slot.interface';
function Slot(_: SlotProps): ReactElement {
return null as unknown as ReactElement;
}
Slot.getSlot = function* getCollectionNode(props: SlotProps): any {
yield props.children;
};
let _Slot = Slot as (props: SlotProps) => JSX.Element;
export default _Slot;
And then, In your component's code, you can use a hook to reduce the children. The hook like this:
import React from 'react';
export function useSlot(children: any) {
const result: Record<string, any> = {
children: []
};
React.Children.map(children, (child: React.ReactElement<any, React.JSXElementConstructor<any>>) => {
if(React.isValidElement(child)){
const type = child.type as any;
const props = child.props;
if(type.name === 'Slot') {
const slot = type.getSlot(child.props);
result[props.name] = slot.next().value;
} else {
result['children'].push(child);
}
} else {
result['children'].push(child);
}
})
return result;
}
the result of the useSlot(children), will be :
{
SubComponentA: 'a',
children: ['b']
}
That is my way to use slot in React. Do you have another way? Please tell me.
Top comments (1)
This is an interesting approach, Ill give it a try.
Strange that React still doesn't support slots while Vue has it by default.
..
Just a heads up that you can add highlighting to the code blocks if you'd like. Just change:
... to specify the language:
More details in our editor guide!