React JSONSchema Form:構建強大且靈活的動態表單

React JSONSchema Form:構建強大且靈活的動態表單
作者: Calpa Liu
字數:1340
出版:2025年3月20日

在當今的 Web 開發中,表單是與用戶交互的最重要界面之一。對於 React 開發者來說,有多種表單解決方案可供選擇,其中 React JSONSchema Form (RJSF) 以其獨特的方式脫穎而出。本文將深入探討這個強大的表單庫,了解如何利用它構建複雜表單,以及如何通過自定義組件提升用戶體驗。

React JSONSchema Form 是一個能夠基於 JSON Schema 自動生成 HTML 表單的 React 組件。它的核心理念是:只需提供一個 JSON Schema 描述數據結構,就能自動生成對應的表單界面。這種方法特別適合處理動態生成的表單,或者基於後端 API 響應構建表單的場景。

React JSONSchema Form
React JSONSchema Form

import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";

const schema = {
  title: "Todo",
  type: "object",
  required: ["title"],
  properties: {
    title: { type: "string", title: "Title", default: "A new task" },
    done: { type: "boolean", title: "Done?", default: false },
  },
};

const log = (type) => console.log.bind(console, type);

const TodoForm = () => (
  <Form
    schema={schema}
    validator={validator}
    onChange={log("changed")}
    onSubmit={log("submitted")}
    onError={log("errors")}
  />
);

構建複雜表單的關鍵技術

JSON Schema
JSON Schema

1. JSON Schema 定義數據結構

使用 React JSONSchema Form 的第一步是定義 JSON Schema,它描述了表單的數據結構、類型和約束。JSON Schema 不僅可以定義基本的數據類型(如字符串、數字、布爾值),還可以處理複雜的嵌套對象和數組。

例如,以下 Schema 定義了一個包含地址和個人信息的複雜表單:

{
  "type": "object",
  "properties": {
    "house_address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      }
    },
    "firstName": { "type": "string" },
    "lastName": { "type": "string" },
    "age": { "type": "number" },
    "telephone": { "type": "string" }
  }
}

2. 利用 uiSchema 自定義界面

雖然 JSON Schema 定義了數據結構,但 uiSchema 則允許開發者自定義表單的外觀和行為。通過 uiSchema,你可以:

  • 重新排序表單字段
  • 應用自定義 widgets 和 fields
  • 添加 CSS 類名
  • 設置自動聚焦、佔位符等 UI 特性
const uiSchema = {
  "ui:order": ["firstName", "lastName", "age", "house_address", "telephone"],
  firstName: {
    "ui:autofocus": true,
    "ui:placeholder": "請輸入名字",
  },
  age: {
    "ui:widget": "updown",
  },
};

3. 表單驗證

React JSONSchema Form 基於 JSON Schema 自動處理表單驗證。你可以在 Schema 中使用 required 屬性標記必填字段,或使用各種驗證關鍵字(如 minimummaximumpattern 等)定義更複雜的驗證規則。

與其他表單構建庫的比較

React JSONSchema Form 與其他流行的表單庫(如 Formik、React Hook Form 和 React Final Form)有著明顯的區別:

聲明式 vs 命令式

RJSF 采用聲明式方法,通過 JSON Schema 描述表單結構,而其他庫通常需要開發者手動編寫每個表單字段。這使得 RJSF 特別適合處理動態表單或從 API 生成的表單。

自動驗證

RJSF 基於 JSON Schema 自動處理表單驗證,而其他庫通常需要開發者編寫自定義驗證邏輯。

性能考量

React Hook Form 專注於最小化重新渲染,因此在非常大的表單中性能可能優於 RJSF。不過,RJSF 對於中小型表單提供了良好的性能和易用性平衡。

使用場景

  • RJSF:最適合動態生成的表單或基於 API 響應的表單
  • React Hook Form/Formik:更適合完全自定義的表單,對每個字段的行為都需要精確控制

自定義組件:提升表單界面

Customization
Customization

RJSF 真正的強大之處在於其可擴展性,允許開發者完全自定義表單的外觀和行為。

自定義 Widgets

Widgets 表示用戶輸入數據的 HTML 標籤,如 inputselect 等。通過自定義 widgets,你可以替換默認的輸入元素:

const CustomCheckbox = function (props) {
  return (
    <button
      id="custom"
      className={props.value ? "checked" : "unchecked"}
      onClick={() => props.onChange(!props.value)}
    >
      {String(props.value)}
    </button>
  );
};

const widgets = {
  CheckboxWidget: CustomCheckbox,
};

<Form schema={schema} uiSchema={uiSchema} widgets={widgets} />;

自定義 Fields

Fields 控制整個表單字段的渲染,包括標籤、幫助文本和輸入元素。自定義 fields 可以完全重寫字段的呈現方式:

class GeoPosition extends React.Component {
  constructor(props) {
    super(props);
    this.state = { ...props.formData };
  }

  onChange(name) {
    return (event) => {
      this.setState(
        {
          [name]: parseFloat(event.target.value),
        },
        () => this.props.onChange(this.state)
      );
    };
  }

  render() {
    const { lat, lon } = this.state;
    return (
      <div className="geo-position-input">
        <input type="number" value={lat} onChange={this.onChange("lat")} />
        <input type="number" value={lon} onChange={this.onChange("lon")} />
      </div>
    );
  }
}

const uiSchema = { "ui:field": "geo" };
const fields = { geo: GeoPosition };

<Form schema={schema} uiSchema={uiSchema} fields={fields} />;

自定義模板

模板允許你重構表單的整體布局。例如,使用 FieldTemplate 自定義每個表單行的布局:

function CustomFieldTemplate(props) {
  const {
    id,
    classNames,
    label,
    help,
    required,
    description,
    errors,
    children,
  } = props;
  return (
    <div className={classNames}>
      <label htmlFor={id}>
        {label}
        {required ? "*" : null}
      </label>
      {description}
      <div className="custom-field-container">{children}</div>
      {errors}
      {help}
    </div>
  );
}

<Form schema={schema} FieldTemplate={CustomFieldTemplate} />;

實際應用案例

React JSONSchema Form 特別適合以下場景:

  1. 動態表單:根據用戶選擇或 API 響應動態調整表單結構
  2. 管理界面:通過 JSON Schema 快速生成 CRUD 操作界面
  3. 複雜的多步驟表單:結合自定義模板創建分步驟表單體驗
  4. 基於配置的表單系統:允許非技術人員通過配置定義表單

使用技巧與最佳實踐

  1. 分解複雜表單:對於非常複雜的表單,考慮將其分解為多個小型表單
  2. 利用 definitions:使用 JSON Schema 的 definitions 部分重用常見的模式
  3. 主題化:使用 RJSF 的主題支持,確保表單與應用程序的整體設計一致
  4. 性能優化:對於大型表單,考慮使用記憶化技術減少不必要的重新渲染

結論

React JSONSchema Form 代表了一種强大而靈活的表單構建方法,通過聲明式的 JSON Schema 定義數據結構,同時提供豐富的自定義選項。它特別適合動態表單生成和快速開發場景,與傳統的命令式表單庫形成了有益的互補。

雖然 React Hook Form 等庫在某些極端性能需求的情況下可能更合適,但 RJSF 的聲明式方法和自動化功能使其成為許多 Web 開發者的首選。通過掌握其自定義機制,開發者可以創建既符合業務邏輯又提供出色用戶體驗的表單界面。

感謝您閱讀我的文章。歡迎隨時分享你的想法。
關於 Calpa

Calpa 擅長使用 TypeScriptReact.jsVue.js 建立 Responsive Website。

他積極參與開源社區,曾在 2019 年的香港開源大會上擔任講者,提供工作經驗和見解。此外,他也在 GitHub 上公開分享個人博客程式碼,已獲得超過 300 顆星星和 60 個分支的支持。

他熱愛學習新技術,並樂意分享經驗。他相信,唯有不斷學習才能跟上快速演變的技術環境。