组成组件时,经常会出现自定义组件内容的任务。例如,我们有一个DatePicker组件,我们需要在Web应用程序的不同部分显示不同的Apply按钮。
为了解决这些问题,当今的每一种流行技术都使用“插槽”的概念。Angular具有ngContent,Vue,Svelte和WebComponents具有插槽。如今,只有流行的React库没有完整的插槽概念。
在React中有几种方法可以解决这个问题:
组件可以完全呈现其所有子代,也可以通过React.Children API对其进行“爬升”并逐点操作子代
组件可以声明所谓的renderProps,并在正确的位置渲染从它们返回的内容:
<MyComponent renderFooter={data => (<h1>Bye, ${data.name}</h1>)}/>
renderProps方法通常众所周知,没有基本缺陷。与成熟的插槽相比,除非使用起来不太方便。NPM有几个库,例如react-view-slot,但我认为它们不够方便,最重要的是,仅解决问题即可。
我决定尝试修复此致命缺陷,现在我将告诉您如何。
我看到了目标-我没有看到实施
在编写任何东西之前,了解要获取的API很有用。这是我想要的结果的草图:
const Component = props => {
Component.NameSlot = useSlot(props.children);
return (
<div>
<h1>
<Component.NameSlot.Receiver>
Default value
</Component.NameSlot.Receiver>
</h1>
Hello {props.children}
</div>
);
};
function App() {
return (
<div>
Hello!
<Component>
Foo
<Component.NameSlot>
Bobobo
</Component.NameSlot>
</Component>
</div>
);
}
这个想法是创建必要的插槽并将功能组件存储在静态属性中,然后在发送和接收端适当地使用它。
, . – , , , -, . , , API, :
import {createSlot} from 'react-slotify';
export const MySlot = createSlot();
export const Component = ({children}) => {
return (
<div>
This component contains slot:
<MySlot.Renderer childs={children}>
This is default slot content
</MySlot.Renderer>
<div>It also renders children: {children}</div>
</div>
);
};
import {Component, MySlot} from './component';
const App = () => {
return (
<div>
<Component>
<MySlot>Slotted content</MySlot>
Other content
</Component>
</div>
);
};
, API, , – MySlot, {children}, , MySlot.Renderer. , JS-, :
export function createSlot() {
const Slot = ({ children, showChildren }) => {
return showChildren ? children : null;
}
const Renderer = ({ childs, children }) => {
const slotted = React.Children.toArray(childs).find(child => {
return React.isValidElement(child) && child.type === Slot;
});
if (!slotted || !React.isValidElement(slotted)) {
return children;
}
return React.cloneElement(slotted, { showChildren: true });
};
Slot.Renderer = Renderer;
return Slot;
}
-, 20 . , React- , . . – Slot. , :
export function createSlot() {
const Slot = ({ children, showChildren }) => {
return showChildren ? children : null;
}
return Slot;
}
, Slot – , showChildren={true}. , , Slot .
– Renderer. – -, Slot-, , showChildren={true}:
const Renderer = ({ childs, children }) => {
const slotted = React.Children.toArray(childs).find(child => {
return React.isValidElement(child) && child.type === Slot;
});
if (!slotted || !React.isValidElement(slotted)) {
return children;
}
return React.cloneElement(slotted, { showChildren: true });
};
, Renderer , , Slot . .
– Renderer Slot, : <MySlot.Renderer/>.
因此,在20行代码中,我们实现了一个概念,这是许多其他技术开发人员非常喜欢的,而React却没有。
我发表的成品实施的反应,slotify库在GitHub上,并作为一个包NPM。已经在TypeScript中并且支持插槽的参数化。我很高兴收到建设性的批评。