# FormRenderer 生命周期钩子指南

## 概述

`FormRenderer` 提供了完整的表单生命周期钩子，允许你在表单提交的各个阶段插入自定义逻辑。

## 钩子执行顺序

```
用户点击提交
    ↓
1. 表单验证 (Form.validateFields)
    ↓ (验证失败)
    onError ← 触发
    ↓ (验证通过)
2. beforeSubmit 钩子
    ↓ (返回 false 或抛出错误)
    onError ← 触发 (可选)
    ↓ (返回修改后的数据或继续)
3. onSubmit 钩子 (执行实际提交)
    ↓ (提交失败)
    onError ← 触发
    ↓ (提交成功)
4. afterSubmit 钩子
    ↓
完成
```

## 钩子详解

### 1. beforeSubmit

**触发时机**: 表单验证通过后，实际提交前

**作用**:
- 预处理表单数据（格式化、转换等）
- 添加额外字段（如时间戳、用户 ID）
- 条件判断，取消提交

**签名**:
```typescript
beforeSubmit?: (values: Record<string, any>) => 
  Record<string, any> | false | Promise<Record<string, any> | false>
```

**返回值**:
- `Record<string, any>` - 修改后的数据，将传递给 `onSubmit`
- `false` - 取消提交，不执行 `onSubmit` 和 `afterSubmit`
- 抛出异常 - 触发 `onError`，中断提交流程

**示例**:
```tsx
const handleBeforeSubmit = async (values) => {
  // 数据预处理
  return {
    ...values,
    email: values.email.toLowerCase(),
    submitTime: new Date().toISOString(),
    userId: getCurrentUserId(),
  };
};

// 条件取消提交
const handleBeforeSubmitWithCondition = async (values) => {
  if (!values.agreeToTerms) {
    message.warning('请先同意服务条款');
    return false; // 取消提交
  }
  return values;
};

<FormRenderer
  schema={schema}
  beforeSubmit={handleBeforeSubmit}
  onSubmit={handleSubmit}
/>
```

### 2. onSubmit

**触发时机**: `beforeSubmit` 执行完成后（如果有）

**作用**:
- 执行实际的提交逻辑
- 调用后端 API
- 返回提交结果

**签名**:
```typescript
onSubmit?: (values: Record<string, any>) => void | Promise<any>
```

**参数**:
- `values` - 如果有 `beforeSubmit`，则是其返回的数据；否则是原始表单数据

**返回值**:
- 返回的结果会传递给 `afterSubmit`

**示例**:
```tsx
const handleSubmit = async (data) => {
  try {
    const response = await api.createUser(data);
    message.success('用户创建成功！');
    return response; // 返回结果给 afterSubmit
  } catch (error) {
    // 错误会被捕获，触发 onError
    throw error;
  }
};

<FormRenderer
  schema={schema}
  onSubmit={handleSubmit}
/>
```

### 3. afterSubmit

**触发时机**: `onSubmit` 成功完成后

**作用**:
- 提交成功后的后续操作
- 页面跳转
- 刷新列表
- 显示成功提示

**签名**:
```typescript
afterSubmit?: (response?: any) => void | Promise<void>
```

**参数**:
- `response` - `onSubmit` 的返回值

**注意**:
- `afterSubmit` 的错误不会中断提交流程，只会记录日志
- 即使 `afterSubmit` 抛出异常，提交仍然被视为成功

**示例**:
```tsx
const handleAfterSubmit = async (response) => {
  // 跳转到详情页
  if (response?.id) {
    navigate(`/users/${response.id}`);
  }
  
  // 刷新列表
  await refreshUserList();
  
  // 关闭弹窗
  setModalVisible(false);
};

<FormRenderer
  schema={schema}
  onSubmit={handleSubmit}
  afterSubmit={handleAfterSubmit}
/>
```

### 4. onError

**触发时机**: 
- 表单验证失败
- `beforeSubmit` 抛出异常
- `onSubmit` 抛出异常

**作用**:
- 统一的错误处理
- 错误上报
- 自定义错误提示

**签名**:
```typescript
onError?: (error: any) => void | Promise<void>
```

**参数**:
- `error` - 错误对象（可能是验证错误、网络错误等）

**示例**:
```tsx
const handleError = async (error) => {
  // 错误上报
  reportError({
    type: 'form_submit_error',
    error: error.message,
    stack: error.stack,
  });
  
  // 自定义错误提示
  if (error.code === 'DUPLICATE_EMAIL') {
    message.error('该邮箱已被注册，请使用其他邮箱');
  } else {
    message.error(`提交失败: ${error.message}`);
  }
};

<FormRenderer
  schema={schema}
  onSubmit={handleSubmit}
  onError={handleError}
/>
```

## 完整示例

```tsx
import React from 'react';
import { FormRenderer } from '@/components/FormDesigner';
import { message } from 'antd';
import { useNavigate } from 'react-router-dom';

const UserCreateForm: React.FC = () => {
  const navigate = useNavigate();
  
  // 1️⃣ beforeSubmit: 数据预处理
  const handleBeforeSubmit = async (values: Record<string, any>) => {
    console.log('📝 原始表单数据:', values);
    
    // 数据格式化
    const processedValues = {
      ...values,
      email: values.email?.toLowerCase(),
      phone: values.phone?.replace(/\s/g, ''),
      submitTime: new Date().toISOString(),
      submittedBy: getCurrentUserId(),
    };
    
    // 条件验证
    if (values.age < 18) {
      message.warning('用户年龄必须大于18岁');
      return false; // 取消提交
    }
    
    console.log('✅ 处理后的数据:', processedValues);
    return processedValues;
  };
  
  // 2️⃣ onSubmit: 执行提交
  const handleSubmit = async (data: Record<string, any>) => {
    console.log('📤 提交到服务器:', data);
    
    // 调用 API
    const response = await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    const result = await response.json();
    console.log('✅ 服务器响应:', result);
    message.success('用户创建成功！');
    
    return result;
  };
  
  // 3️⃣ afterSubmit: 提交成功后的处理
  const handleAfterSubmit = async (response: any) => {
    console.log('🎉 提交完成，开始后续处理:', response);
    
    // 延迟跳转
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 跳转到用户详情页
    navigate(`/users/${response.data.id}`);
  };
  
  // 4️⃣ onError: 错误处理
  const handleError = async (error: any) => {
    console.error('❌ 提交出错:', error);
    
    // 上报错误
    await reportError({
      type: 'user_create_error',
      message: error.message,
      timestamp: Date.now(),
    });
    
    // 自定义错误提示
    if (error.message.includes('duplicate')) {
      message.error('该邮箱已被注册');
    } else if (error.message.includes('network')) {
      message.error('网络错误，请稍后重试');
    } else {
      message.error(`创建失败: ${error.message}`);
    }
  };
  
  return (
    <FormRenderer
      schema={formSchema}
      beforeSubmit={handleBeforeSubmit}
      onSubmit={handleSubmit}
      afterSubmit={handleAfterSubmit}
      onError={handleError}
      showSubmit
      showCancel
      submitText="创建用户"
      cancelText="取消"
    />
  );
};
```

## 常见场景

### 场景1: 添加额外字段

```tsx
const handleBeforeSubmit = async (values) => {
  return {
    ...values,
    createdBy: getCurrentUser().id,
    createdAt: Date.now(),
    source: 'web',
  };
};
```

### 场景2: 数据格式转换

```tsx
const handleBeforeSubmit = async (values) => {
  return {
    ...values,
    // 日期对象转 ISO 字符串
    startDate: values.startDate?.toISOString(),
    endDate: values.endDate?.toISOString(),
    // 数组转逗号分隔字符串
    tags: values.tags?.join(','),
    // 金额转分（后端存储）
    amount: Math.round(values.amount * 100),
  };
};
```

### 场景3: 二次确认

```tsx
const handleBeforeSubmit = async (values) => {
  const confirmed = await new Promise((resolve) => {
    Modal.confirm({
      title: '确认提交',
      content: `确定要创建用户 "${values.username}" 吗？`,
      onOk: () => resolve(true),
      onCancel: () => resolve(false),
    });
  });
  
  return confirmed ? values : false;
};
```

### 场景4: 提交后跳转或刷新

```tsx
const handleAfterSubmit = async (response) => {
  // 方式1: 跳转到列表页
  navigate('/users');
  
  // 方式2: 跳转到详情页
  navigate(`/users/${response.id}`);
  
  // 方式3: 刷新当前页面数据
  await refreshData();
  
  // 方式4: 关闭弹窗
  setModalVisible(false);
};
```

### 场景5: 错误分类处理

```tsx
const handleError = async (error) => {
  if (error.code === 400) {
    message.error('请求参数错误，请检查输入');
  } else if (error.code === 401) {
    message.error('登录已过期，请重新登录');
    navigate('/login');
  } else if (error.code === 403) {
    message.error('没有权限执行此操作');
  } else if (error.code === 409) {
    message.error('数据冲突，请刷新后重试');
  } else if (error.code >= 500) {
    message.error('服务器错误，请联系管理员');
  } else {
    message.error(`提交失败: ${error.message}`);
  }
};
```

## 最佳实践

### ✅ 推荐

1. **明确职责分离**
   ```tsx
   // ✅ beforeSubmit 只做数据处理
   beforeSubmit: (values) => ({ ...values, email: values.email.toLowerCase() })
   
   // ✅ onSubmit 只做网络请求
   onSubmit: (data) => api.createUser(data)
   
   // ✅ afterSubmit 只做后续操作
   afterSubmit: () => navigate('/success')
   ```

2. **使用 async/await**
   ```tsx
   // ✅ 清晰的异步处理
   const handleSubmit = async (data) => {
     const response = await api.createUser(data);
     return response;
   };
   ```

3. **统一错误处理**
   ```tsx
   // ✅ 在 onError 中统一处理
   onError: (error) => {
     reportError(error);
     showErrorMessage(error);
   }
   ```

### ❌ 避免

1. **不要在 beforeSubmit 中做网络请求**
   ```tsx
   // ❌ 不推荐
   beforeSubmit: async (values) => {
     await api.checkDuplicate(values.email); // 应该在 onSubmit 中做
     return values;
   }
   ```

2. **不要在 afterSubmit 中处理错误**
   ```tsx
   // ❌ 错误应该在 onError 中处理
   afterSubmit: (response) => {
     if (!response.success) {
       message.error('失败'); // 应该在 onError 中做
     }
   }
   ```

3. **避免循环依赖**
   ```tsx
   // ❌ 不要在钩子中再次触发提交
   afterSubmit: () => {
     form.submit(); // 会导致无限循环
   }
   ```

## 调试技巧

```tsx
const handleBeforeSubmit = async (values) => {
  console.group('🎣 beforeSubmit');
  console.log('原始数据:', values);
  const processed = processData(values);
  console.log('处理后:', processed);
  console.groupEnd();
  return processed;
};

const handleSubmit = async (data) => {
  console.group('📤 onSubmit');
  console.log('提交数据:', data);
  try {
    const response = await api.submit(data);
    console.log('响应:', response);
    return response;
  } catch (error) {
    console.error('错误:', error);
    throw error;
  } finally {
    console.groupEnd();
  }
};

const handleAfterSubmit = async (response) => {
  console.log('🎉 afterSubmit:', response);
};

const handleError = async (error) => {
  console.error('❌ onError:', error);
};
```

## 总结

生命周期钩子让你能够在表单提交的各个阶段插入自定义逻辑：

- **beforeSubmit**: 预处理数据，可取消提交
- **onSubmit**: 执行实际提交
- **afterSubmit**: 提交成功后的处理
- **onError**: 统一的错误处理

合理使用这些钩子，可以构建健壮、灵活的表单提交流程。

