From b12bce24fd0398abe807281d3e35c11b4936ece3 Mon Sep 17 00:00:00 2001 From: quirkyvar Date: Wed, 25 Mar 2020 15:46:27 +0800 Subject: [PATCH] doc(next/antd): array item docs optimization (#749) --- docs/zh-cn/SUMMARY.md | 1 - docs/zh-cn/jsx-develop/complex-linkage.md | 793 +++++++++++++++++- docs/zh-cn/jsx-develop/form-layout.md | 247 ++++++ .../complext-self-inc-component.md | 405 ++++++++- .../schema-develop/self-inc-component.md | 283 ------- .../antd-components/src/array-table/index.tsx | 6 +- packages/antd/README.zh-cn.md | 1 - .../next-components/src/array-table/index.tsx | 6 +- packages/next/README.zh-cn.md | 1 - scripts/docs.js | 2 +- 10 files changed, 1447 insertions(+), 298 deletions(-) delete mode 100644 docs/zh-cn/schema-develop/self-inc-component.md diff --git a/docs/zh-cn/SUMMARY.md b/docs/zh-cn/SUMMARY.md index 19cc45190ec..d330239317e 100644 --- a/docs/zh-cn/SUMMARY.md +++ b/docs/zh-cn/SUMMARY.md @@ -16,7 +16,6 @@ - [性能优化实践](./schema-develop/performance.md) - [管理业务逻辑](./schema-develop/manage-business.md) - [实现递归渲染组件](./schema-develop/recursive-render.md) - - [实现自增列表组件](./schema-develop/self-inc-component.md) - [玩转自增列表组件](./schema-develop/complext-self-inc-component.md) - [实现超复杂自定义组件](./schema-develop/create-complex-field-component.md) - [FAQ](./schema-develop/faq.md) diff --git a/docs/zh-cn/jsx-develop/complex-linkage.md b/docs/zh-cn/jsx-develop/complex-linkage.md index bfd470dddb3..7418393525b 100644 --- a/docs/zh-cn/jsx-develop/complex-linkage.md +++ b/docs/zh-cn/jsx-develop/complex-linkage.md @@ -1 +1,792 @@ -# 介绍 +# 实现复杂联动逻辑 + +我们的联动逻辑的复杂度通常取决于是否存在以下几种问题: + +- 联动类型复杂 + - 一对多联动 + - 多对一联动 + - 多依赖联动 + - 链式联动 + - 循环联动 + - 联动校验 +- 联动过程中存在异步 +- 联动过程中存在大量数据转换逻辑 +- 自增列表中相邻字段或者与上一级/下一级字段间的联动 +- 动态联动,这里主要讲的是 JSON Schema 中的动态联动,比如是用户手工配置联动规则 + +上面分析那么多,其实每种问题都是比较麻烦的,一不小心,就会把代码变得非常难以维护,所以我们在解决这类复杂问题的时候,更多的是需要寻找一个可以优雅分解问题的解题策略。 + +直接看例子: + +## 一对多联动 + +```jsx +import React, { useEffect } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + createFormActions, + FormEffectHooks, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { Input, Select } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const useOneToManyEffects = () => { + const { setFieldState } = createFormActions() + + onFieldValueChange$('aa').subscribe(({ value }) => { + setFieldState('*(bb,cc,dd)', state => { + state.visible = value + }) + }) +} + +const App = () => { + return ( + +
{ + console.log(values) + }} + effects={() => { + useOneToManyEffects() + }} + > + + + + + +
+ ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 使用 FormEffectHooks 可以很方便的将联动逻辑拆分出去,方便我们进行物理分离 +- 借助路径系统的批量匹配能力实现一对多联动 + +## 多对一联动 + +```jsx +import React, { useEffect } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + createFormActions, + FormEffectHooks, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { Input, Select } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const useManyToOneEffects = () => { + const { setFieldState } = createFormActions() + onFieldValueChange$('bb').subscribe(({ value }) => { + setFieldState('aa', state => { + state.visible = value + }) + }) + onFieldValueChange$('cc').subscribe(({ value }) => { + setFieldState('aa', state => { + state.value = value + }) + }) +} + +const App = () => { + return ( + +
{ + console.log(values) + }} + effects={() => { + useManyToOneEffects() + }} + > + + + + +
+ ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 多对一联动其实就是一对一联动,只不过作用的对象是同一个字段 +- BB 控制 AA 显示隐藏,CC 控制 AA 的值 + +## 多依赖联动 + +```jsx +import React, { useEffect } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + createFormActions, + FormEffectHooks, + createEffectHook, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { combineLatest } from 'rxjs/operators' +import { Input, Select } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$, onFormMount$ } = FormEffectHooks + +const customEvent$ = createEffectHook('CUSTOM_EVENT') + +const useMultiDepsEffects = () => { + const { setFieldState, dispatch } = createFormActions() + + onFormMount$().subscribe(() => { + setTimeout(() => { + dispatch('CUSTOM_EVENT', true) + }, 3000) + }) + + onFieldValueChange$('aa') + .pipe(combineLatest(customEvent$())) + .subscribe(([{ value, values }, visible]) => { + setFieldState('bb', state => { + state.visible = visible + }) + setFieldState('cc', state => { + state.visible = value + if (values[1] && values[1].otherInfo) { + state.value = values[1].otherInfo + } + }) + }) +} + +const App = () => { + return ( + +
{ + console.log(values) + }} + effects={() => { + useMultiDepsEffects() + }} + > + + + + +
+ ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- FormItem 组件 visible 属性可以控制初始显示状态 +- BB 的显示受外部异步事件所控制 +- CC 的显示隐藏状态受 AA 的值控制,CC 的值受 AA 的附加信息所控制,同时整体联动依赖一个外部异步事件 +- 使用 rxjs 操作符 combineLatest 可以解决联动异步依赖问题 + +## 链式联动 + +```jsx +import React, { useEffect } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + createFormActions, + FormEffectHooks, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { Input, Select } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const useChainEffects = () => { + const { setFieldState } = createFormActions() + onFieldValueChange$('aa').subscribe(({ value }) => { + setFieldState('bb', state => { + state.visible = value + }) + }) + onFieldValueChange$('bb').subscribe(({ value }) => { + setFieldState('cc', state => { + state.visible = value + }) + }) +} + +const App = () => { + return ( + +
{ + console.log(values) + }} + effects={() => { + useChainEffects() + }} + > + + + + +
+ ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 链式联动,其实也是可以归一化为一对一联动 +- AA 控制 BB 显示隐藏,BB 控制 CC 隐藏 + +## 循环联动 + +> 联动关系 Total = Price \* Count;Count = Total / Price;Price = Total / Count + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + Submit, + Reset, + FormEffectHooks, + createFormActions +} from '@formily/antd' +import { NumberPicker } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFormInit$, onFieldValueChange$ } = FormEffectHooks + +const useCyclicLinkageEffects = () => { + const { setFieldState, getFieldState } = createFormActions() + onFieldValueChange$('total').subscribe(({ value }) => { + if (!value) return + setFieldState('count', state => { + const price = getFieldState('price', state => state.value) + if (!price) return + state.value = value / price + }) + setFieldState('price', state => { + const count = getFieldState('count', state => state.value) + if (!count) return + state.value = value / count + }) + }) + onFieldValueChange$('price').subscribe(({ value }) => { + if (!value) return + setFieldState('total', state => { + const count = getFieldState('count', state => state.value) + if (!count) return + state.value = value * count + }) + setFieldState('count', state => { + const total = getFieldState('total', state => state.value) + if (!total) return + state.value = total / value + }) + }) + onFieldValueChange$('count').subscribe(({ value }) => { + if (!value) return + setFieldState('total', state => { + const price = getFieldState('price', state => state.value) + if (!price) return + state.value = value * price + }) + setFieldState('price', state => { + const total = getFieldState('total', state => state.value) + if (!total) return + state.value = total / value + }) + }) +} + +const App = () => ( + +
{ + useCyclicLinkageEffects() + }} + onChange={v => console.log(v)} + labelCol={6} + wrapperCol={4} + onSubmit={v => console.log(v)} + > + + + + + + + + +
+) +ReactDOM.render(, document.getElementById('root')) +``` + +**案例详解** + +- 循环联动,其实也是可以归一到一对一联动的 + +## 联动校验 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + Submit, + Reset, + FormEffectHooks, + createFormActions +} from '@formily/antd' +import { Input, Password } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const useLinkageValidateEffects = () => { + const { setFieldState, getFieldState } = createFormActions() + onFieldValueChange$('*(password,confirm)').subscribe(fieldState => { + const selfName = fieldState.name + const selfValue = fieldState.value + const otherName = selfName == 'password' ? 'confirm' : 'password' + const otherValue = getFieldState(otherName, state => state.value) + setFieldState(otherName, state => { + if (selfValue && otherValue && selfValue !== otherValue) { + state.errors = '两次密码输入不一致' + } else { + state.errors = '' + } + }) + setFieldState(selfName, state => { + if (selfValue && otherValue && selfValue !== otherValue) { + state.errors = '两次密码输入不一致' + } else { + state.errors = '' + } + }) + }) +} + +const App = () => ( + +
{ + useLinkageValidateEffects() + }} + > + + +
  • 1. 长度不小于8个
  • +
  • 2. 必须包含大小写数字符号
  • + + } + required + component={Password} + /> + + + + + + +
    +) +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 联动校验都需要手动操作字段状态的 errors 属性来控制,你既需要控制错误的出现时机,也要控制错误的隐藏时机 + +## 异步联动 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + Submit, + Reset, + FormEffectHooks, + createFormActions, + FormPath +} from '@formily/antd' +import { Select, Input } from '@formily/antd-components' +import { merge } from 'rxjs' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFormInit$, onFieldValueChange$, onFieldInit$ } = FormEffectHooks + +const createLinkageUtils = () => { + const { setFieldState } = createFormActions() + const linkage = (key, defaultValue) => (path, value) => + setFieldState(path, state => { + FormPath.setIn(state, key, value !== undefined ? value : defaultValue) + }) + return { + hide: linkage('visible', false), + show: linkage('visible', true), + enum: linkage('props.enum', []), + loading: linkage('loading', true), + loaded: linkage('loading', false), + value: linkage('value') + } +} + +const useAsyncLinkageEffect = () => { + const linkage = createLinkageUtils() + onFieldValueChange$('aa').subscribe(fieldState => { + if (!fieldState.value) return + linkage.show('bb') + linkage.loading('bb') + setTimeout(() => { + linkage.loaded('bb') + linkage.enum('bb', ['1111', '2222']) + linkage.value('bb', '1111') + }, 1000) + }) + merge(onFieldValueChange$('bb'), onFieldInit$('bb')).subscribe( + fieldState => { + if (!fieldState.value) return linkage.hide('cc') + linkage.show('cc') + linkage.value('cc', fieldState.value) + } + ) +} + +const App = () => ( + +
    { + useAsyncLinkageEffect() + }} + onChange={v => console.log(v)} + labelCol={6} + wrapperCol={4} + onSubmit={v => console.log(v)} + > + + + + + + + + +
    +) +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 借助 createFormActions,我们可以创建出一些可复用的联动操作原子函数 + +## 自增列表联动 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Button } from 'antd' +import { + Form, + FormItem, + FieldList, + FormButtonGroup, + FormEffectHooks, + createFormActions, + FormPath, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { Input, Select } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const App = () => { + return ( + +
    { + console.log(values) + }} + effects={({ setFieldState }) => { + onFieldValueChange$('array.*.aa').subscribe(({ name, value }) => { + setFieldState( + FormPath.transform(name, /\d/, $1 => { + return `array.${$1}.bb` + }), + state => { + state.visible = value + } + ) + }) + }} + > + + {({ state, mutators }) => { + const onAdd = () => mutators.push() + return ( +
    + {state.value.map((item, index) => { + return ( +
    + + +
    + ) + })} + +
    + ) + }} +
    +
    +
    + ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 借助 FormPath.transform 可以求出自增列表字段的相邻字段 + +## 外部联动 + +```jsx +import React, { useEffect } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + createFormActions, + FormEffectHooks, + FormSpy, + Submit, + Reset +} from '@formily/antd' // 或者 @formily/next +import { Input, Select } from '@formily/antd-components' +import { Button } from 'antd' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const { onFieldValueChange$ } = FormEffectHooks + +const useOneToManyEffects = () => { + const { setFieldState } = createFormActions() + onFieldValueChange$('aa').subscribe(({ value }) => { + setFieldState('*(bb,cc,dd)', state => { + state.visible = value + }) + }) +} + +const actions = createFormActions() + +const App = () => { + return ( + +
    { + useOneToManyEffects() + }} + > + + + + + + + {({ state }) => { + return ( + state.value && ( + <> + + + + ) + ) + }} + + + +
    + ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 主联动逻辑是一对多联动 +- 借助 FormSpy 可以针对具体字段做监听,所以可以很方便的做 UI 联动状态同步 +- 借助 FormActions 可以方便的在外部操作 Form 内部状态 diff --git a/docs/zh-cn/jsx-develop/form-layout.md b/docs/zh-cn/jsx-develop/form-layout.md index e69de29bb2d..e6ba62f493a 100644 --- a/docs/zh-cn/jsx-develop/form-layout.md +++ b/docs/zh-cn/jsx-develop/form-layout.md @@ -0,0 +1,247 @@ +# 实现复杂布局 + +## 内联布局 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Form, FormItem, FormButtonGroup, Submit, Reset } from '@formily/antd' +import { Input, DatePicker, NumberPicker } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const App = () => ( + +
    + + + ​ + + 提交重置​ + + +
    +) +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 给 Form 组件传入 inline 属性即可把表单变成内联模式 + +## 复杂组合布局 + +```jsx +import React, { useState } from 'react' +import ReactDOM from 'react-dom' +import { + Form, + FormItem, + FormButtonGroup, + Submit, + Reset, + FormEffectHooks, + FormItemDeepProvider as FormLayout, + InternalVirtualField as VirtualField +} from '@formily/antd' +import { Button, Card, Row, Col } from 'antd' +import Printer from '@formily/printer' +import { + Input, + Radio, + Checkbox, + Select, + DatePicker, + NumberPicker, + TimePicker, + Upload, + Switch, + Range, + Transfer, + Rating +} from '@formily/antd-components' // 或者@formily/next-components +import 'antd/dist/antd.css' + +const App = () => { + const [state, setState] = useState({ editable: true }) + return ( + +
    { + FormEffectHooks.onFieldValueChange$('bbb').subscribe(({ value }) => { + setFieldState('detailCard', state => { + state.visible = value + }) + }) + FormEffectHooks.onFieldValueChange$('ccc').subscribe(({ value }) => { + setFieldState('layout_1', state => { + state.visible = value + }) + }) + }} + labelCol={8} + wrapperCol={6} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + 元/票 退 + + 元/票 改 + + 元/票 +
    +
    +
    + ​ + + + + +
    +
    + ​提交​ + + 重置​ + +
    +
    + ) +} +ReactDOM.render(, document.getElementById('root')) +``` + +**案例解析** + +- 开发者可以自由选择布局方式进行开发 + +## 网格布局 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Row, Col } from 'antd' +import { Form, FormItem, FormButtonGroup, Submit, Reset } from '@formily/antd' +import { FormItemGrid, Input } from '@formily/antd-components' +import Printer from '@formily/printer' +import 'antd/dist/antd.css' + +const App = () => ( + +
    console.log(v)}> + + + + + + + + + + + + + + + + + + + + + + ​提交重置​ + +
    +
    +) +ReactDOM.render(, document.getElementById('root')) +``` diff --git a/docs/zh-cn/schema-develop/complext-self-inc-component.md b/docs/zh-cn/schema-develop/complext-self-inc-component.md index 35ff53d9c50..faa5c5e202d 100644 --- a/docs/zh-cn/schema-develop/complext-self-inc-component.md +++ b/docs/zh-cn/schema-develop/complext-self-inc-component.md @@ -4,7 +4,7 @@ ### 基础使用 -**Formily** 内置 **ArrayCards**, **ArrayTable** ,使用方式完全一致,主要差异在UI上。下面用 **ArrayTable** 举例, 示例如下: +**Formily** 内置 **ArrayCards**, **ArrayTable** 作为官方自增列表组件,两者使用方式完全一致,主要差异在UI上。下面用 **ArrayTable** 举例(**ArrayCards**同理), 代码如下: ```tsx import { SchemaForm, SchemaMarkupField as Field } from '@formily/antd' @@ -29,7 +29,382 @@ const App = () => ( ) ``` -### 使用useFormEffects实现局部联动 +### ArrayTable 和 ArrayCards + +底层均是基于 [ArrayList](https://github.com/alibaba/formily/blob/master/packages/react-shared-components/src/ArrayList.tsx) 的,不过承载的容器组件分别是 **Table** 和 **Card**, DEMO如下: + +```jsx +import React, { useState } from 'react' +import ReactDOM from 'react-dom' +import { Button } from 'antd' +import { Schema, SchemaForm, SchemaMarkupField as Field } from '@formily/antd' +import { Input, ArrayTable, ArrayCards } from '@formily/antd-components' +import'antd/dist/antd.css' + +const App = () => { + return ( + + + + + + + + + + + + + + + + ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +### 如何定制按钮及操作渲染 + +| 属性名 | 说明 | 类型 | +|:----------|:---------------------------------|:--------------------| +| renderAddition | 自定义添加按钮内容 | () => React.ReactElement | +| renderRemove | 自定义删除按钮内容 | (index: Number) => React.ReactElement | +| renderMoveDown | 自定义向下移动按钮内容 | (index: Number) => React.ReactElement | +| renderMoveUp | 自定义向上移动按钮内容 | (index: Number) => React.ReactElement | +| renderEmpty | 自定义渲染空数据内容 | (index: Number) => React.ReactElement | +| renderExtraOperations | 自定义渲染额外操作按钮内容 | (index: Number) => React.ReactElement | + + +通过以上属性可以复写并自定义操作按钮,以下会演示几个常见场景。 + +1. 自定义添加图标 +2. 隐藏上移,下移图标 +3. 根据当行的值决定是否显示删除图标 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Button } from 'antd' +import styled from 'styled-components' +import { FormSpy, createFormActions, SchemaForm, SchemaField, SchemaMarkupField as Field } from '@formily/antd' +import { Input, ArrayCards } from '@formily/antd-components' +import'antd/dist/antd.css' + +const actions = createFormActions() +const App = () => { + return ( + + null, + renderMoveUp: () => null, + renderAddition: () => '+add', + renderRemove: (idx) => { + return + {({ state }) => state.value === 'morally' ? null : 'remove'} + + } + }} + > + + + + + + + ) +} + +ReactDOM.render(, document.getElementById('root')) + +``` + + +### ArrayTable专属定制属性 + +除了上述属性外,**ArrayTable** 还支持以下属性 + +| 属性名 | 说明 | 类型 | +|:----------|:---------------------------------|:--------------------| +| operations | 为false时不展示操作列,作为Table.Column的props传入 | { [key: string]: any } `or` false | +| operationsWidth | 操作列宽度 | number | +| draggable | 是否启用拖拽模式 | boolean | + +下面例子来展示下如何使用上述属性 + +```jsx +import React from 'react' +import ReactDOM from 'react-dom' +import { Button } from 'antd' +import styled from 'styled-components' +import { FormSpy, createFormActions, SchemaForm, SchemaField, SchemaMarkupField as Field } from '@formily/antd' +import { Input, ArrayTable } from '@formily/antd-components' +import'antd/dist/antd.css' + +const actions = createFormActions() +const App = () => { + return ( + + + + + + + + + ) +} + +ReactDOM.render(, document.getElementById('root')) + +``` + +## 拓展定制专属自增列表 + +### 简单版本 + +这个版本旨在快速讲清楚如何实现自增组件,仅需要 **25** 行代码就能实现一个 `Formily` 自增组件。可以点击 [IMutators](#IMutators) 了解更多API。 + +```tsx +import { Button } from 'antd' +import { SchemaForm, SchemaField, toArr, FormPath } from '@formily/antd' + +const ArrayCustom = (props) => { + const { value, schema, className, editable, path, mutators } = props; + const componentProps = schema.getExtendsComponentProps() || {} + const onAdd = () => mutators.push(schema.items.getEmptyValue()) + const onRemove = (index) => mutators.remove(index) + const onMoveUp = (index) => mutators.moveUp(index) + const onMoveDown = (index) => mutators.moveDown(index) + + return
    + {toArr(value).map((item, index) => ( +
    + + + + +
    + ))} + +
    +} +ArrayCustom.isFieldComponent = true +``` + +### 生产级别版本 + +为了编写更**健壮**的自增列表组件,我们会用到 `@formily/react-shared-components` 的 [ArrayList](https://github.com/alibaba/formily/blob/master/packages/react-shared-components/src/ArrayList.tsx) + +**ArrayList** 已经内置了通用的自增列表逻辑,只需要配置它们即可。 + +```tsx + - - - - ))} - - -} -ArrayCustom.isFieldComponent = true -``` - -## 生产级别版本 - -为了编写更**健壮**的自增列表组件,我们会用到 `@formily/react-shared-components` 的 [ArrayList](https://github.com/alibaba/formily/blob/master/packages/react-shared-components/src/ArrayList.tsx) - -## 认识ArrayList - -**ArrayList** 已经内置了通用的自增列表逻辑,只需要配置它们即可。 - -```tsx -