flutter-bloc-forms

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Form Architecture with BLoC

基于BLoC的表单架构

  • Manage form state in a dedicated
    FormBloc
    — NOT in widget
    setState
  • Each form field maps to a property in the BLoC state
  • Validate on field change (real-time) or on submit (batch) depending on UX requirements
  • Emit
    FormSubmitting
    ,
    FormSuccess
    ,
    FormError
    states for submission flow
  • 在专门的
    FormBloc
    中管理表单状态,不要在组件的
    setState
    中管理
  • 每个表单字段映射到BLoC状态中的一个属性
  • 根据UX需求选择字段变更时实时验证或提交时批量验证
  • 为提交流程触发
    FormSubmitting
    FormSuccess
    FormError
    状态

Form Events

表单事件

  • FieldChanged(field, value)
    — update a single field in state
  • FormSubmitted
    — trigger validation and submission
  • FormReset
    — clear all fields and errors
  • FieldChanged(field, value)
    — 更新状态中的单个字段
  • FormSubmitted
    — 触发验证和提交逻辑
  • FormReset
    — 清空所有字段和错误信息

Form State

表单状态

  • Use a single state class with all field values, field-level errors, and form status:
    dart
    sealed class FormStatus { initial, submitting, success, failure }
  • Field errors:
    Map<String, String?>
    keyed by field name —
    null
    means valid
  • 使用单个状态类存储所有字段值、字段级错误和表单状态:
    dart
    sealed class FormStatus { initial, submitting, success, failure }
  • 字段错误:以字段名为键的
    Map<String, String?>
    ,值为
    null
    代表校验通过

Validation Patterns

验证模式

  • Validate in the domain layer — NOT in widgets or BLoCs
  • Create pure validator functions that return
    String?
    (null = valid, string = error message):
    dart
    String? validateEmail(String value) =>
      value.contains('@') ? null : 'Invalid email';
  • Compose validators:
    String? validate(String v) => validateRequired(v) ?? validateEmail(v)
  • Use localized error messages via
    context.l10n
    — no hardcoded validation strings
  • 在领域层进行验证,不要在组件或BLoC中做验证
  • 创建纯验证函数,返回
    String?
    (null = 校验通过,字符串 = 错误信息):
    dart
    String? validateEmail(String value) =>
      value.contains('@') ? null : 'Invalid email';
  • 组合验证器:
    String? validate(String v) => validateRequired(v) ?? validateEmail(v)
  • 通过
    context.l10n
    使用本地化错误信息,不要硬编码验证字符串

Input Widgets

输入组件

  • Use
    TextFormField
    with
    InputDecoration
    for consistent styling
  • Always set
    textInputAction
    for proper keyboard behavior (
    next
    ,
    done
    )
  • Always set
    keyboardType
    matching the field type (
    emailAddress
    ,
    phone
    ,
    number
    )
  • Use
    inputFormatters
    to restrict input (e.g.,
    FilteringTextInputFormatter.digitsOnly
    )
  • Assign
    Key('feature_fieldName')
    to every form field for test access
  • Use
    AutofillHints
    for login/signup forms (email, password, name)
  • Wrap form fields with
    Focus
    or
    FocusTraversalGroup
    for proper tab order
  • 使用带
    InputDecoration
    TextFormField
    保证样式统一
  • 始终设置
    textInputAction
    以获得正确的键盘行为(
    next
    done
  • 始终设置与字段类型匹配的
    keyboardType
    emailAddress
    phone
    number
  • 使用
    inputFormatters
    限制输入内容(例如
    FilteringTextInputFormatter.digitsOnly
  • 为每个表单字段分配
    Key('feature_fieldName')
    以便测试时访问
  • 登录/注册表单使用
    AutofillHints
    (邮箱、密码、姓名)
  • Focus
    FocusTraversalGroup
    包裹表单字段以保证正确的tab切换顺序

Controller Lifecycle

控制器生命周期

  • Declare
    TextEditingController
    as
    late final
    in
    initState()
    — dispose in
    dispose()
  • Sync controllers to BLoC via
    onChanged
    callback or controller listener
  • initState()
    中声明为
    late final
    类型的
    TextEditingController
    ,在
    dispose()
    中销毁
  • 通过
    onChanged
    回调或控制器监听器将控制器与BLoC同步

Form Submission

表单提交

  • Disable submit button while
    FormStatus.submitting
    to prevent double-submission
  • Show inline field errors below each field — not just a top-level error
  • On success: navigate, show success feedback, and reset form if staying on same page
  • On failure: show error feedback via
    SnackBar
    or inline, keep form data intact
  • FormStatus.submitting
    时禁用提交按钮,防止重复提交
  • 在每个字段下方显示行内字段错误,不要只展示顶层错误
  • 提交成功:跳转页面、展示成功提示,如果停留在当前页则重置表单
  • 提交失败:通过
    SnackBar
    或行内提示展示错误反馈,保留表单数据

Common Form Patterns

常见表单模式

  • Search: Use
    debounce
    transformer on search events (300-500ms delay)
  • Multi-step: Each step is a separate form state within one
    FormBloc
    , validated independently
  • Dependent fields: Update dependent field options in
    on<FieldChanged>
    handler (e.g., country → city)
  • 搜索:在搜索事件上使用
    debounce
    转换器(300-500ms延迟)
  • 多步骤:每个步骤是同一个
    FormBloc
    下的独立表单状态,单独验证
  • 依赖字段:在
    on<FieldChanged>
    处理器中更新依赖字段的选项(例如国家 → 城市)