没什么好看的,请路过。
React 与 Ant Design 开发关键点
1. 定义变量
- React 中变量可以通过
useState
定义。 useState
定义的变量会触发页面更新。
示例:
tsx
复制代码
import React, { useState } from 'react';
const MyComponent: React.FC = () => {
const [count, setCount] = useState(0); // 定义 count 变量,初始值为 0
const increment = () => setCount(count + 1); // 修改变量
return (
<div>
<p>当前计数:{count}</p>
<button onClick={increment}>增加计数</button>
</div>
);
};
export default MyComponent;
2. 使用 Ref
- Ref 用于直接操作 DOM 或保存一些不会触发重新渲染的变量。
- 在 React 中使用
useRef
。
示例:操作输入框:
tsx
复制代码
import React, { useRef } from 'react';
const MyInput: React.FC = () => {
const inputRef = useRef<HTMLInputElement>(null); // 创建 ref
const focusInput = () => {
inputRef.current?.focus(); // 直接聚焦输入框
};
return (
<div>
<input ref={inputRef} type="text" placeholder="输入内容" />
<button onClick={focusInput}>聚焦输入框</button>
</div>
);
};
export default MyInput;
3. 父子组件传参
父组件可以通过 props
向子组件传递数据和回调函数。
父组件传递数据:
tsx
复制代码
import React from 'react';
import Child from './Child';
const Parent: React.FC = () => {
const handleSubmit = (data: string) => {
console.log('子组件传来的数据:', data);
};
return <Child name="React 新人" onSubmit={handleSubmit} />;
};
export default Parent;
子组件接收数据:
tsx
复制代码
import React from 'react';
interface ChildProps {
name: string;
onSubmit: (data: string) => void;
}
const Child: React.FC<ChildProps> = ({ name, onSubmit }) => {
return (
<div>
<p>你好,{name}!</p>
<button onClick={() => onSubmit('子组件提交的数据')}>提交数据</button>
</div>
);
};
export default Child;
4. 表单与提交数据
Ant Design 提供了强大的表单组件,可以方便地获取用户输入。
使用 Antd 表单组件:
tsx
复制代码
import React from 'react';
import { Form, Input, Button } from 'antd';
const MyForm: React.FC = () => {
const [form] = Form.useForm(); // 创建表单实例
const handleFinish = (values: any) => {
console.log('表单提交数据:', values);
};
return (
<Form form={form} onFinish={handleFinish}>
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
);
};
export default MyForm;
表单验证:
- 使用
rules
定义表单字段的验证规则。 onFinish
方法会在验证通过后提交表单数据。
5. 数据提交
数据提交通常通过封装好的请求库(如 axios
)向后端发送请求。
封装请求库:
ts
复制代码
// src/utils/request.ts
import axios from 'axios';
const request = axios.create({
baseURL: 'https://api.example.com', // 后端 API 地址
timeout: 5000, // 超时时间
});
// 添加请求拦截器
request.interceptors.request.use(
(config) => {
// 在请求头中添加 token
config.headers['Authorization'] = 'Bearer your-token';
return config;
},
(error) => Promise.reject(error)
);
export default request;
表单提交后发送请求:
tsx
复制代码
import React from 'react';
import { Form, Input, Button, message } from 'antd';
import request from '../utils/request';
const MyForm: React.FC = () => {
const [form] = Form.useForm();
const handleFinish = async (values: any) => {
try {
const response = await request.post('/submit', values); // 提交数据到后端
message.success('提交成功!');
console.log('服务器响应:', response.data);
} catch (error) {
message.error('提交失败,请重试!');
console.error('提交失败:', error);
}
};
return (
<Form form={form} onFinish={handleFinish}>
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
);
};
export default MyForm;
在 React 中,父组件调用子组件的表单校验是否完整,可以通过 ref
和 useImperativeHandle
暴露子组件的表单校验方法给父组件。以下是一个完整的实现示例。
实现:父组件调用子组件表单校验
6. 子组件定义表单及校验方法
在子组件中:
- 使用 Ant Design 的
Form
组件管理表单。 - 使用
forwardRef
和useImperativeHandle
将表单校验逻辑暴露给父组件。
tsx
复制代码
// 子组件:ApplicantForm.tsx
import React, { forwardRef, useImperativeHandle } from 'react';
import { Form, Input, Button } from 'antd';
export interface ApplicantFormRef {
validateForm: () => Promise<any>;
}
const ApplicantForm = forwardRef<ApplicantFormRef>((_, ref) => {
const [form] = Form.useForm();
// 暴露给父组件的方法
const validateForm = async () => {
try {
const values = await form.validateFields(); // 表单校验
console.log('表单数据:', values);
return values; // 返回表单数据
} catch (error) {
console.error('校验失败:', error);
throw error; // 抛出错误,供父组件捕获
}
};
// 使用 useImperativeHandle 暴露方法
useImperativeHandle(ref, () => ({
validateForm,
}));
return (
<Form form={form} layout="vertical">
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="邮箱"
name="email"
rules={[{ required: true, type: 'email', message: '请输入有效的邮箱地址!' }]}
>
<Input />
</Form.Item>
</Form>
);
});
export default ApplicantForm;
2. 父组件调用子组件校验方法
在父组件中:
- 使用
useRef
引用子组件。 - 在需要时调用子组件暴露的
validateForm
方法。
tsx
复制代码
// 父组件:ParentComponent.tsx
import React, { useRef } from 'react';
import { Button, message } from 'antd';
import ApplicantForm, { ApplicantFormRef } from './ApplicantForm';
const ParentComponent: React.FC = () => {
const formRef = useRef<ApplicantFormRef>(null); // 定义 ref 类型
// 点击保存按钮时调用子组件校验方法
const handleSave = async () => {
if (formRef.current) {
try {
const formData = await formRef.current.validateForm(); // 调用子组件校验
console.log('提交的数据:', formData);
message.success('表单校验通过,已提交!');
} catch (error) {
message.error('表单校验未通过,请检查输入!');
}
}
};
return (
<div>
<h1>父组件</h1>
<ApplicantForm ref={formRef} />
<div style={{ marginTop: 20 }}>
<Button type="primary" onClick={handleSave}>
保存
</Button>
</div>
</div>
);
};
export default ParentComponent;
运行逻辑解析
子组件:ApplicantForm
- 定义表单:使用
Form.useForm()
管理表单实例。 - 校验方法:通过
form.validateFields()
实现校验逻辑。 - 暴露方法:用
useImperativeHandle
将validateForm
方法暴露给父组件。
父组件:ParentComponent
- 使用
useRef
获取子组件的引用。 - 在按钮点击事件中,调用子组件的
validateForm
方法,捕获返回值或错误信息。
关键点说明
-
校验方法:
form.validateFields()
:会校验表单字段,若通过则返回数据,若失败则抛出错误。
-
暴露方法:
- 使用
forwardRef
和useImperativeHandle
,使父组件可以调用子组件的逻辑。
- 使用
-
错误处理:
- 在父组件中通过
try-catch
捕获子组件抛出的校验错误,提示用户。
- 在父组件中通过
效果展示
-
初始页面显示子组件表单。
-
点击保存按钮,调用子组件的校验逻辑:
- 如果校验通过,打印数据到控制台,提示“表单校验通过,已提交!”。
- 如果校验失败,提示“表单校验未通过,请检查输入!”。
总结
- 子组件负责表单校验逻辑,父组件通过
ref
调用子组件的校验方法。 useImperativeHandle
是连接父子组件交互的桥梁。- 使用 Ant Design 的
Form
提供的校验机制,可以轻松实现字段验证和数据获取。
这种模式适合处理复杂的表单嵌套逻辑,提高代码可读性和复用性。
如果父组件引用了两个子组件,并需要分别校验两个子组件的表单是否完整,可以通过以下方式实现:
- 为每个子组件分别设置
ref
。 - 在每个子组件中定义独立的表单校验方法,通过
forwardRef
和useImperativeHandle
暴露给父组件。 - 父组件统一调用两个子组件的校验方法,并根据返回值或抛出的错误判断表单是否验证通过。
完整实现示例
子组件定义表单校验方法
每个子组件(如 ChildFormA
和 ChildFormB
)独立管理自己的表单,并暴露校验方法。
子组件 1:ChildFormA
tsx
复制代码
import React, { forwardRef, useImperativeHandle } from 'react';
import { Form, Input } from 'antd';
export interface ChildFormRef {
validateForm: () => Promise<any>;
}
const ChildFormA = forwardRef<ChildFormRef>((_, ref) => {
const [form] = Form.useForm();
// 暴露校验方法
const validateForm = async () => {
try {
const values = await form.validateFields(); // 校验表单
console.log('子组件A表单数据:', values);
return values;
} catch (error) {
console.error('子组件A校验失败:', error);
throw error;
}
};
useImperativeHandle(ref, () => ({
validateForm,
}));
return (
<Form form={form} layout="vertical">
<Form.Item
label="用户名A"
name="usernameA"
rules={[{ required: true, message: '请输入用户名A!' }]}
>
<Input />
</Form.Item>
</Form>
);
});
export default ChildFormA;
子组件 2:ChildFormB
tsx
复制代码
import React, { forwardRef, useImperativeHandle } from 'react';
import { Form, Input } from 'antd';
export interface ChildFormRef {
validateForm: () => Promise<any>;
}
const ChildFormB = forwardRef<ChildFormRef>((_, ref) => {
const [form] = Form.useForm();
// 暴露校验方法
const validateForm = async () => {
try {
const values = await form.validateFields(); // 校验表单
console.log('子组件B表单数据:', values);
return values;
} catch (error) {
console.error('子组件B校验失败:', error);
throw error;
}
};
useImperativeHandle(ref, () => ({
validateForm,
}));
return (
<Form form={form} layout="vertical">
<Form.Item
label="用户名B"
name="usernameB"
rules={[{ required: true, message: '请输入用户名B!' }]}
>
<Input />
</Form.Item>
</Form>
);
});
export default ChildFormB;
7. 父组件统一调用子组件的校验方法
父组件通过 useRef
分别获取两个子组件的引用,并在提交时逐一调用其 validateForm
方法。
tsx
复制代码
import React, { useRef } from 'react';
import { Button, message } from 'antd';
import ChildFormA, { ChildFormRef } from './ChildFormA';
import ChildFormB from './ChildFormB';
const ParentComponent: React.FC = () => {
const formARef = useRef<ChildFormRef>(null); // 子组件A的ref
const formBRef = useRef<ChildFormRef>(null); // 子组件B的ref
const handleSave = async () => {
try {
// 分别校验两个子组件的表单
const formAValues = await formARef.current?.validateForm();
const formBValues = await formBRef.current?.validateForm();
console.log('子组件A数据:', formAValues);
console.log('子组件B数据:', formBValues);
message.success('所有表单校验通过!');
} catch (error) {
message.error('请检查表单是否填写完整!');
}
};
return (
<div>
<h1>父组件</h1>
<ChildFormA ref={formARef} />
<ChildFormB ref={formBRef} />
<div style={{ marginTop: 20 }}>
<Button type="primary" onClick={handleSave}>
提交
</Button>
</div>
</div>
);
};
export default ParentComponent;
代码解析
-
子组件暴露校验方法
- 使用
forwardRef
和useImperativeHandle
,将validateForm
方法暴露给父组件。 validateForm
方法使用form.validateFields()
校验表单,并返回表单数据。
- 使用
-
父组件管理多个子组件的引用
- 父组件通过
useRef
创建多个引用,用于分别引用子组件。 - 调用子组件的
validateForm
方法时,注意添加空值检查。
- 父组件通过
-
统一校验逻辑
- 在
handleSave
方法中,依次调用两个子组件的校验方法。 - 如果任意一个子组件校验失败,会抛出异常并提示用户。
- 在
运行效果
-
父组件加载时会展示两个子组件的表单。
-
点击提交按钮时:
- 调用
ChildFormA
和ChildFormB
的校验方法。 - 如果校验通过,控制台输出两个表单的数据,并提示“所有表单校验通过!”。
- 如果任意一个表单校验失败,提示“请检查表单是否填写完整!”。
- 调用
优化建议
-
并行校验
- 使用
Promise.all
并行调用两个表单的校验方法,加快校验速度。
tsx 复制代码 const handleSave = async () => { try { const [formAValues, formBValues] = await Promise.all([ formARef.current?.validateForm(), formBRef.current?.validateForm(), ]); console.log('子组件A数据:', formAValues); console.log('子组件B数据:', formBValues); message.success('所有表单校验通过!'); } catch (error) { message.error('请检查表单是否填写完整!'); } };
- 使用
-
代码复用
- 如果多个子组件的表单结构和逻辑相似,可以提取公共逻辑到自定义 Hook 中,避免重复代码。
总结
-
核心方法:
forwardRef
:用于让子组件接受父组件的ref
。useImperativeHandle
:用于在子组件中定义暴露给父组件的方法。useRef
:用于在父组件中管理子组件的引用。
-
校验逻辑:
- 每个子组件独立校验,父组件统一调用。
- 使用
form.validateFields()
进行表单验证。
-
扩展:
- 通过
Promise.all
并行处理多个表单校验,提高性能。
- 通过