Slot 和 Fill 是一对组件,使开发者能够在 React 元素树的其他位置渲染 React UI,这种模式通常被称为“portal”渲染。这是一种组件扩展性模式,单个 Slot 可以被应用不同部分中渲染的多个 Fill 所占据。
Slot/Fill 最初受到 react-slot-fill 库 的启发。
用法
在应用的根节点处,必须渲染一个 SlotFillProvider,以协调 Slot 和 Fill 的渲染。
然后,在应用的任何位置渲染一个 Slot 组件,并为其指定一个 name。name 可以是 string 或 symbol。Symbol 名称对于旨在私有的插槽非常有用,仅允许拥有该 symbol 值的客户端访问。
任何 Fill 都会在此 Slot 空间中渲染其 UI,即使它是在应用的其他位置渲染的。
您可以直接使用 Fill 组件,或者创建一个包装组件(如下例所示),以向使用者隐藏插槽名称。
import {
SlotFillProvider,
Slot,
Fill,
Panel,
PanelBody,
} from '@wordpress/components';
const MySlotFillProvider = () => {
const MyPanelSlot = () => (
<Panel header="Panel with slot">
<PanelBody>
<Slot name="MyPanelSlot" />
</PanelBody>
</Panel>
);
MyPanelSlot.Content = () => <Fill name="MyPanelSlot">Panel body</Fill>;
return (
<SlotFillProvider>
<MyPanelSlot />
<MyPanelSlot.Content />
</SlotFillProvider>
);
};
还有一个 createSlotFill 辅助方法,它是为了简化匹配相应的 Slot 和 Fill 组件的过程而创建的:
const { Fill, Slot } = createSlotFill( 'Toolbar' );
const ToolbarItem = () => <Fill>My item</Fill>;
const Toolbar = () => (
<div className="toolbar">
<Slot />
</div>
);
Props
SlotFillProvider 组件不接受任何 props(children 除外)。
Slot 和 Fill 都接受一个 name 字符串 prop,具有给定 name 的 Slot 将渲染任何关联的 Fill 的 children。
Slot 接受一个 bubblesVirtually prop,它改变了渲染 Fill children 的方法。使用 bubblesVirtually 时,Fill 是使用 React portal 渲染的。这会影响事件冒泡和 React context 传播行为:
bubblesVirtually=false
- 事件将冒泡到 DOM 层次结构中的父级(原生事件冒泡)
Fill内的 React 元素将以Slot的 React context 进行渲染- 直接在
Fragment内渲染Fill元素,没有包装 DOM 元素
bubblesVirtually=true
- 事件将冒泡到 React 元素层次结构中的虚拟(React)父级
Fill内的 React 元素将保留Fill及其父级的 React context- 渲染一个包装 DOM 元素,在其中渲染
Fill元素(用作 ReactcreatePortal的参数)
bubblesVirtually=true 的 Slot 会渲染一个包装 DOM 元素(默认为 div),并接受自定义此元素的额外 props,如 className 或 style。您还可以通过传递 as prop 将 div 替换为其他元素。
不带 bubblesVirtually 的 Slot 接受一个可选的 children prop,它是一个接收 fills 数组作为参数的函数。它允许您执行额外的处理:当没有 fills 时渲染占位符,或者仅在存在 fills 时渲染包装器。
示例:
const Toolbar = ( { isMobile } ) => (
<div className="toolbar">
<Slot name="Toolbar">
{ ( fills ) => {
return isMobile && fills.length > 3 ? (
<div className="toolbar__mobile-long">{ fills }</div>
) : (
fills
);
} }
</Slot>
</div>
);
附加信息(props)也可以通过以下组合从 Slot 传递给 Fill:
1. 向 Slot 添加 fillProps prop。
2. 将函数作为 children 传递给 Fill。该函数将接收 fillProps 作为参数。
const { Fill, Slot } = createSlotFill( 'Toolbar' );
const ToolbarItem = () => (
<Fill>
{ ( { hideToolbar } ) => {
<Button onClick={ hideToolbar }>Hide</Button>;
} }
</Fill>
);
const Toolbar = () => {
const hideToolbar = () => {
console.log( 'Hide toolbar' );
};
return (
<div className="toolbar">
<Slot fillProps={ { hideToolbar } } />
</div>
);
};