可视化搭建会遇到如下三类容器组件:
- 简略容器:以
children
包容子组件的容器。 - 卡片容器:以
props.header
加上props.header
等多个插槽包容子组件的容器。 - Tab 容器:以
props.tabPanel[x]
等动静数量插槽包容子组件的容器。
画布自身也是一个容器组件,所以可视化搭建离不开容器。
另一方面,咱们应该容许给组件 props 传入 React 组件实例,但组件树是可序列化的 JSON 构造,因而须要一种定义形式,将某些属性转化为 React 组件实例传给组件实例。
容器的定义
任何组件都可能是容器组件,只有它将 props.children
或 props.footer
等任何属性作为 ReactNode 渲染。因而咱们不须要非凡申明组件是否为容器,而仅需将某些组件 Key 申明为 ReactNode 节点。
Children
children
因为太罕用因而独自强调进去,能够只在在组件实例定义 children
属性,它为是一个数组:
import {ComponentInstance} from "designer";
const componentTree: ComponentInstance = {
componentName: "div",
children: [
{componentName: "input",},
],
};
对于这个组件,Designer 会将 children
定义的属性了解为组件实例,并真正解析为 React 实例传递给 props.children
,因而组件渲染代码能够间接应用 children
渲染:
import {ComponentMeta} from "designer";
const divMeta: ComponentMeta = {
componentName: "div",
element: ({children}) => <div>{children}</div>,
};
这种约定的益处是直观天然,组件代码也没有关怀到框架逻辑,自然而然实现了容器性能。
treeLike 构造
只有将任意组件 props 定义为数组模式,并且蕴含 componentName
,Designer 就认为应该解析为 ReactNode。
如上面的例子,咱们定义的 div
组件初始化就会渲染一个 input
组件在 props.header
地位:
import {ComponentMeta} from "designer";
const divMeta: ComponentMeta = {
componentName: "div",
element: ({header}) => <div>{header}</div>,
defaultProps: {
header: [
{componentName: "input",},
],
},
};
也能够在形容组件树时间接写在对应 props 地位:
import {ComponentInstance} from "designer";
const componentTree: ComponentInstance = {
componentName: "div",
props: {
header: [
{componentName: "input",},
],
},
};
这种约定的益处是直观的反对了任意 props key 为组件实例,但仍然存在限度,因而 Designer 还须要反对一种用户 100% 掌控的申明式定义:propTypes
。
PropTypes
在组件元信息 propTypes
属性定义更粗疏的容器插槽地位,比方:
const tabMeta = {
componentName: "tab",
propTypes: {
tabs: [
{panel: "element",},
],
},
};
那么当组件实例如下定义时:
const componentInstance = {
componentName: "tab",
props: {
tabs: [
{
title: "tab1",
panel: {componentName: "card",},
},
{
title: "tab2",
panel: {componentName: "text",},
},
],
},
};
组件拿到的 props.tabs[0].panel
就是一个能够间接渲染的 React 组件实例,因为在 propTypes
定义了 tabs[].panel
门路是一个组件实例。
这样设计须要思考组件树遍历的问题,因为组件实例地位定义在组件元信息上,因而仅靠组件树无奈做遍历(因为遍历父节点时,不联合 componentMeta
就无奈确认哪些 props 地位是子组件实例),这样会带来两个问题:
- 遍历组件十分麻烦,极其状况下,如果大量组件是近程注册的三方组件,会导致须要一层层串行近程拉取组件实例,导致遍历过程变慢。
- 更极其的场景是,当组件版本升级导致
propTypes
变动,一些本来不是组件实例的地位成为了组件实例,或者反之,此时拉取最新组件元信息读取的propTypes
可能就是错的。
因为以上两个起因,实现计划应该是将组件元信息定义的 propTypes
拷贝一份到组件实例,这样就能够仅凭组件树本身来遍历组件树了,而且定义在组件树上的 propTypes
肯定对应以后组件树的构造。
总结
咱们通过 children
与 props 上 treeLike 这两个约定,实现了业务根本够用的容器定义能力,仅凭这两个约定就能够实现简直所有容器须要的成果。
propTypes 定义补全了约定拓展性的有余,让 props 任何地位都可能成为组件实例,只须要付出额定定义 propTypes 的代价。
浏览到这,置信你曾经了解到,可视化搭建其实不存在容器组件的概念,因为这个组件之所以是容器,仅仅因为它的某个 prop 属性是组件实例,而它恰好将该属性渲染到某个地位(甚至用 createPortal
挂载到其余 dom 节点),所以它仅仅是一种 prop 属性的体现,因而对容器组件,咱们没有设计一种新 type
,而是容许任意地位属性定义为实例。
下一节咱们会介绍为组件元信息增加取数与筛选联动的钩子,让筛选器 + 查问场景能够轻松被实现。
探讨地址是:精读《容器组件设计》· Issue #468 · dt-fe/weekly
如果你想参加探讨,请 点击这里,每周都有新的主题,周末或周一公布。前端精读 – 帮你筛选靠谱的内容。
关注 前端精读微信公众号
<img width=200 src=”https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg”>
版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)