聊一聊我对 React Context 的理解以及应用(5)

<div> <header> <slot></slot> </header> <main> <slot></slot> </main> <footer> <slot></slot> </footer> </div>

而在父组件模板中:

<app-layout> <h1 slot="header">这里可能是一个页面标题</h1> <p>主要内容的一个段落。</p> <p>另一个段落。</p> <p slot="footer">这里有一些联系信息</p> </app-layout>

最终渲染的结果:

<div> <header> <h1>这里可能是一个页面标题</h1> </header> <main> <p>主要内容的一个段落。</p> <p>另一个段落。</p> </main> <footer> <p>这里有一些联系信息</p> </footer> </div>

插槽分发的好处体现在,它可以让组件具有可抽象成模板的能力。组件自身只关心模板结构,具体的内容交给父组件去处理,同时,不打破HTML描述DOM结构的语法表达方式。我觉得这是一项很有意义的技术,可惜,React对于这项技术的支持不是那么友好。于是我便参考Vuejs的插槽分发组件,开发了一套基于React的插槽分发组件,可以让React组件也具模板化的能力。

对于<AppLayout />组件,我希望可以写成下面这样:

class AppLayout extends React.Component { static displayName = 'AppLayout' render () { return ( <div> <header> <Slot></Slot> </header> <main> <Slot></Slot> </main> <footer> <Slot></Slot> </footer> </div> ) } }

在外层使用时,可以写成这样:

<AppLayout> <AddOn slot="header"> <h1>这里可能是一个页面标题</h1> </AddOn> <AddOn> <p>主要内容的一个段落。</p> <p>另一个段落。</p> </AddOn> <AddOn slot="footer"> <p>这里有一些联系信息</p> </AddOn> </AppLayout>

组件的实现思路

根据前面所想的,先整理一下实现思路。

不难看出,插槽分发组件需要依靠两个子组件——插槽组件<Slot />和分发组件<AddOn />。插槽组件,负责打桩,提供分发内容的坑位。分发组件,负责收集分发内容,并提供给插槽组件去渲染分发内容,相当于插槽的消费者。

显然,这里遇到了一个问题,<Slot />组件与<AddOn />组件是独立的,如何将<AddOn />的内容填充到<Slot />中呢?解决这个问题不难,两个独立的模块需要建立联系,就给他们建立一个桥梁。那么这个桥梁要如何搭建呢?回过头来看看之前的设想的代码。

对于<AppLayout />组件,希望写成下面这样:

class AppLayout extends React.Component { static displayName = 'AppLayout' render () { return ( <div> <header> <Slot></Slot> </header> <main> <Slot></Slot> </main> <footer> <Slot></Slot> </footer> </div> ) } }

在外层使用时,写成这样:

<AppLayout> <AddOn slot="header"> <h1>这里可能是一个页面标题</h1> </AddOn> <AddOn> <p>主要内容的一个段落。</p> <p>另一个段落。</p> </AddOn> <AddOn slot="footer"> <p>这里有一些联系信息</p> </AddOn> </AppLayout>

无论是<Slot />还是<AddOn />,其实都在<AppLayout />的作用域内。<Slot />是<AppLayout />组件render()方法返回的组件节点,而<AddOn />则是<AppLayout />的children节点,所以,可以将<AppLayout />视为<Slot />与<AddOn />的桥梁的角色。那么,<AppLayout />通过什么给<Slot />和<AddOn />建立联系呢?这里就用到本文的主角——Context。接下来的问题就是,如何使用Context给<Slot />和<AddOn />建立联系?

前面提到了<AppLayout />这座桥梁。在外层组件,<AppLayout />负责通过<AddOn />收集为插槽填充的内容。<AppLayout />自身借助Context定义一个获取填充内容的接口。在渲染的时候,因为<Slot />是<AppLayout />渲染的节点,所以,<Slot />可以通过Context获取到<AppLayout />定义的获取填充内容的接口,然后通过这个接口,获取到填充内容进行渲染。

按照思路实现插槽分发组件

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsdgxg.html