Skip to content
Return to top
On this page

# defineFatForm 定义器 #

和 `defineFatTable` 类似， 我们也提供了 defineFatForm 用于快速定义表单。相比直接使用 `<template>`， defineFatForm 可以提供更好的类型提示和检查。

## Hello world #

查看代码
tsx

    import { defineFatForm } from '@wakeadmin/components';

    export default defineFatForm<{
      // 🔴 这里的泛型变量可以定义表单数据结构
      name: string;
      nickName: string;
    }>(({ item, form, consumer, group }) => {
      // 🔴 这里可以放置 Hooks

      // 🔴 form 为 FatForm 实例引用
      console.log(form);

      // 返回表单定义
      return () => ({
        // FatForm props 定义
        initialValue: {
          name: 'ivan',
          nickName: '狗蛋',
        },

        // 🔴 子节点
        children: [
          item({ prop: 'name', label: '账号名' }),
          item({
            prop: 'nickName',
            label: '昵称',
          }),

          // 🔴 这里甚至可以放 JSX
          <div>JSX hello</div>,

          // 🔴 不过，如果你想要监听 表单数据，还是建议使用 FatFormConsumer, 否则会导致整个表单的重新渲染
          // 不信，你可以打开 Vue 开发者工具的 Highlight Updates 试一下
          consumer(({ values }) => {
            return group({
              label: '表单状态',
              children: (
                <pre>
                  <code>{JSON.stringify(values, null, 2)}</code>
                </pre>
              ),
            });
          }),
        ],
      });
    });

`defineFatForm` 使用方法类似于 Vue 的 `defineComponent`, 只不过返回一个 `DSL`, 这个 DSL 定义了表单的结构和配置信息。

## 定义结构 #

defineFatForm 的 `DSL` 需要满足类似 `<template>` 的灵活结构的同时，保持一定约束性。为此我们提供了一些 `helpers` 来辅助你定义这个 DSL，并且能关联类型上下文。

- `group` 定义 `FatFormGroup`
- `item` 定义 `FatFormItem`
- `section` 定义 `FatFormSection`
- `consumer` 定义 `FatFormConsumer`

底层方法

- renderChild 可以将上述辅助转换为 JSX 节点
- renderChildren 和 renderChild 类似，只不过支持接收一个数组

上述 `helper` 接收对应组件的 Props，除了 `item` , `group`、`section` 还支持传入一个 `children` 字段, 用于定义下级节点:

tsx

    defineFatForm(({ item, group, section, consumer }) => {
      return () => ({
        // 这里放置 FatForm 的 Props
        // ...

        // 定义下级节点
        children: [
          group({
            children: [
              // group 支持下级节点
            ],
          }),
          section({
            children: [
              // section 支持下级节点
              group({
                // 可以逐级嵌套
                children: [],
              }),
            ],
          }),
          consumer(() => {
            // consumer 回调的返回值等价于 children
            return [];
          }),
        ],
      });
    });

`children` 支持传入 `item`、`group`、`section`、`consumer`, 以及 JSX:

tsx

    defineFatForm(({ item, group, section, consumer }) => {
      return () => ({
        // 定义下级节点
        children: [
          group({
            /*..*/
          }),
          item({
            /*..*/
          }),
          section({
            /*..*/
          }),
          consumer(() => {
            /*..*/
          }),
          <div>JSX</div>,
          someCondition && <div>JSX</div>,
        ],
      });
    });

## 为什么推荐使用 `consumer` 而不是直接写 `JSX` #

如果想要实现表单联动等, 依赖于表单数据的渲染，我们推荐使用 consumer, 因为它能够实现精确渲染。下面对比两个示例(打开 Vue 开发者工具的 Highlight Updates 查看重新渲染的范围):

查看代码
tsx

    import { defineFatForm } from '@wakeadmin/components';

    export const UseConsumer = defineFatForm(({ item, consumer }) => {
      return () => ({
        children: [
          item({ label: 'a', prop: 'a' }),
          item({ label: 'b', prop: 'b' }),
          item({ label: 'c', prop: 'c' }),
          consumer(({ values }) => {
            return <div>{JSON.stringify(values)}</div>;
          }),
        ],
      });
    });

    /**
     * 未使用 consumer, 将导致全量渲染
     */
    export const NotUseConsumer = defineFatForm(({ item, form }) => {
      return () => ({
        children: [
          item({ label: 'a', prop: 'a' }),
          item({ label: 'b', prop: 'b' }),
          item({ label: 'c', prop: 'c' }),
          <div>{JSON.stringify(form.value?.values)}</div>,
        ],
      });
    });