基于 Ant Design
, 咱们来实现一个【薪资调查表】,需求有二:html
职位(Job)列表
模拟从服务端拉取 react
当职位是 Student
时,薪资(Income)
输入框消失。 web
咱们先用 Ant Design 提供的 Form, Input, Select, Button
组件来构建 UI 架构。数组
labelCol
为 label
标签布局,wrapperCol
为输入控件设置布局样式,使用方式同 Grid 栅格。markdown
使用 <Button htmlType="submit" />
调用 web 原生提交逻辑。antd
import { Form, Input, Select, Button } from 'antd';
const { Option } = Select;
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 12 },
};
const DynamicForm = () => {
return (
<Form {...layout}> <Form.Item name="name" label="User Name"> <Input /> </Form.Item> <Form.Item name="job" label="Job"> <Select placeholder="Select a option and change input text above"> <Option>loading</Option> </Select> </Form.Item> <Form.Item name="income" label="Income"> <Input /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit"> Submit </Button> </Form.Item> </Form>
);
};
export default DynamicForm;
复制代码
基础 UI 框架完成后,咱们来实现开头的两个逻辑需求。架构
先介绍一下 useState 和 useEffect 两个 Hooks 吧:app
const [state, setState] = useState(initialState);
复制代码
它会返回一个 state
,以及更新 state
的函数。框架
initialState
会做为 state
的初始值。函数
useEffect(didUpdate);
复制代码
该 Hook 接收一个包含命令式、且可能有反作用代码的函数。
赋值给 useEffect
的函数会在组件渲染到屏幕以后执行,改变 DOM、添加订阅、设置定时器、记录日志以及执行其余包含反作用的操做,能够放在 useEffect
里执行。
组件卸载时须要清除 effect
建立的诸如订阅或计时器 ID 等资源。要实现这一点,useEffect
函数需返回一个清除函数,咱们在下面也会用到。
默认状况下,effect
会在每轮组件渲染完成后执行。然而,咱们只想在某些特定条件下执行 effect
,该怎么办呢?
要实现这一点,能够给 useEffect
传递第二个参数,只有当 props.source
改变后才会从新建立订阅。
useEffect(didiUpdate, [props.source]);
复制代码
import { useState, useEffect } from 'react';
const DynamicForm = () => {
const [jobs, setJobs] = useState([]);
useEffect(() => {
const timer = setTimeout(() => {
setJobs(['engineer', 'student', 'doctor']);
}, 2000);
return function clear() {
clearTimeout(timer);
};
}, []); // [],只执行一次
return;
};
复制代码
在列表数据拉取完成以后,遍历 jobs
渲染下拉项:
<Select>
{jobs.length > 0 ? (
jobs.map((job) => (
<Option key={job} value={job}> {job} </Option>
))
) : (
<Option>loading</Option>
)}
</Select>
复制代码
当 Job
字段值为 Student
时,Income
输入框须要隐藏。这样的话,咱们须要能获取 Job
的字段值。
在函数组件中,经过 Form.useForm
对表单数据域进行交互。getFieldValue
方法能够获取对应字段名的值。
const DynamicForm = () => {
const [form] = Form.useForm();
return (
<Form form={form} > {({ getFieldValue }) => getFieldValue('job') !== 'student' ? ( <Form.Item name="income" label="Income" > <Input /> </Form.Item> ) : null } </Form>
};
复制代码
咱们但愿在修改 Job
字段值后更新 Income
输入控件的显隐,shouldUpdate
能够帮助咱们实现这个更新逻辑。
<Form.Item
shouldUpdate={(prevValues, currentValues) =>
prevValues.job !== currentValues.job
}
></Form.Item>
复制代码
但这又引起了另外一个问题,<Form.Item name="field" />
只会对它的直接子元素绑定表单功能,就像这样:
<Form.Item label="Field" name="field">
<Input />
</Form.Item>
复制代码
因此咱们须要经过添加 noStyle
将外层 Form.Item
做为纯粹的无样式绑定组件。
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) =>
prevValues.job !== currentValues.job
}
>
{({ getFieldValue }) =>
getFieldValue('job') !== 'student' ? (
<Form.Item name="income" label="Income" rules={[{ required: true }]}> <Input /> </Form.Item>
) : null
}
</Form.Item>
复制代码
import { useState, useEffect } from 'react';
import { Form, Input, Select, Button } from 'antd';
const { Option } = Select;
const DynamicForm = () => {
const [form] = Form.useForm();
const [jobs, setJobs] = useState([]);
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 12 },
};
useEffect(() => {
const timer = setTimeout(() => {
setJobs(['engineer', 'student', 'doctor']);
}, 2000);
return function clear() {
clearTimeout(timer);
};
}, []);
return (
<Form form={form} {...layout}> <Form.Item name="name" label="User Name" rules={[{ required: true }]}> <Input /> </Form.Item> <Form.Item name="job" label="Job" rules={[{ required: true }]}> <Select placeholder="Select a option and change input text above" allowClear > {jobs.length > 0 ? ( jobs.map((job) => ( <Option key={job} value={job}> {job} </Option> )) ) : ( <Option>loading</Option> )} </Select> </Form.Item> <Form.Item noStyle shouldUpdate={(prevValues, currentValues) => prevValues.job !== currentValues.job } > {({ getFieldValue }) => getFieldValue('job') !== 'student' ? ( <Form.Item name="income" label="Income" rules={[{ required: true }]} > <Input /> </Form.Item> ) : null } </Form.Item> <Form.Item> <Button type="primary" htmlType="submit"> Submit </Button> </Form.Item> </Form>
);
};
export default DynamicForm;
复制代码