If you master value/onChange, you will master the essence of form writing.
The management side component has only two purposes:
- Collect data from users
- Show data to users
There are three data formats for collecting data from users:
- The value of the original data type (such as string/number, etc.)
- object
- array
Therefore, the development mode of collecting any data from users is:
- Three input boxes, one interface: value/onChange.
- Input box for collecting raw data type (provided by most antd)
- Input box for collection object
- Collection array input box
- Form is a convenient tool for distributing objects to the next level of input; The form itself is the input of an output object to the upper level.
- The development of collecting nested object forms is to descend level by level. The development can collect the input of each object. This is a recursive process and can be automated.
example
Collect non nested objects
Collect the following objects:
{ "name": "Reward rule name", "desc": "Description of reward rules" }
Directly use the antd form and distribute it to the input collecting the original value:
Form: Input: name Input: desc
Collect nested objects
Collect the following objects:
{ "name": "Reward rule name", "desc": "Description of reward rules" "msg": { "template_id": "323ll1w", "app_id": "app12323" } }
Using the antd form, when distributing to msg:
Form: Input: name Input: desc An input box that can collect objects: msg
We need an input box that can collect objects, and its interface conforms to value/onChange.
Review article 2 of the development model:
Form is a convenient tool for distributing objects to the next level of input; The form itself is the input of an output object to the upper level.
The form itself is a component that can output objects. Just change its interface to value/onChange.
Input box components that can collect msg objects:
import { Form, Input } from 'antd' import React, { FC } from 'react' export const MsgInput: FC<{ value?: any, onChange?: (value: string) => void }> = (props) => { const { value, onChange = (() => { }) } = props const [form] = Form.useForm() const fields = [{ label: 'Template ID', key: 'template_id', jsx: <Input />, }, { label: 'APPID', key: 'app_id', jsx: <Input />, }] const getFields = (fields) => { const children = fields.map(one => ( <Form.Item name={one.key} label={one.label} rules={one.rules} > {one.jsx ? one.jsx : <Input />} </Form.Item> )) return children } return ( <Form form={form} initialValues={value} name='object_input' onValuesChange={(_, values) => { onChange(values) }} > {getFields(fields)} </Form> ) }
This [input box that can collect msg objects] is not far from becoming [input box that can collect any object], for example:
export const CreateObjectInput = (fields) => { return (props) => { const { value, onChange = (() => { }) } = props const [form] = Form.useForm() const getFields = (fields) => { const children = fields.map(one => ( <Form.Item name={one.key} label={one.label} rules={one.rules} > {one.jsx ? one.jsx : <Input />} </Form.Item> )) return children } return ( <Form form={form} initialValues={value} name='object_input' onValuesChange={(_, values) => { onChange(values) }} > {getFields(fields)} </Form> ) } }
Collect nested array objects
For example:
{ "name": "Reward rule name", "desc": "Description of reward rules" "msg": { "template_id": "323ll1w", "app_id": "app12323" }, "msgs": [ { "template_id": "323ll1w", "app_id": "app12323" }, { "template_id": "323ll1w", "app_id": "app12323" }, ] }
Using the antd form, when distributing to msgs:
Form: Input: name Input: desc MsgInput: msg An input box that can collect arrays: msgs
Input box components that can collect msgs arrays:
import { Form } from 'antd' import React, { FC } from 'react' export const MsgsInput: FC<{ value?: any, onChange?: (value: any) => void }> = (props) => { const { value, onChange = (() => { }) } = props const add = () => { onChange([...value, {}]) } const del = () => { const newVal = [...value] newVal.pop() onChange(newVal) } if (!value) { // If it is empty, notify the external first, change it to an empty array, and render at least one table onChange([]) return <Button type='primary' onClick={add}> newly added </Button> } const onOneInputChange = (v, i) => { const copy = [...value] copy[i] = v onChange(copy) } return ( <> {value.map((one, index) => <MsgInput key={index} value={one} onChange={(value) => onOneInputChange(value, index)} />)} <Button type='primary' onClick={add}> newly added </Button> {(value?.length > 1) ? <Button type='default' onClick={del}> delete </Button> : ''} </> ) }
This [input box that can collect msgs arrays] is not far from becoming [input box that can collect any array], for example:
export const CreateArrayInput = (OneInput) => { return (props) => { const { value, onChange = (() => { }) } = props const add = () => { onChange([...value, {}]) } const del = () => { const newVal = [...value] newVal.pop() onChange(newVal) } if (!value) { // If it is empty, notify the external first, change it to an empty array, and render at least one table onChange([]) return <Button type='primary' onClick={add}> newly added </Button> } const onOneInputChange = (v, i) => { const copy = [...value] copy[i] = v onChange(copy) } return ( <> {value.map((one, index) => <OneInput key={index} value={one} onChange={(value) => onOneInputChange(value, index)} />)} <Button type='primary' onClick={add}> newly added </Button> {(value?.length > 1) ? <Button type='default' onClick={del}> delete </Button> : ''} </> ) } }
follow-up
If the three input boxes can be generalized and the mode is fixed, can the form be output automatically given a data to be collected?
To be broken down next time.
Extension: sharing and reuse mechanism
The key of reuse is classification.
- Put your needs into a category,
- Then, according to this category, find the components that meet the requirements.
Therefore, the essence of classification is: a technology for fast positioning solutions.
When providing a range of components, the most important thing is to establish a set of classification criteria:
- Each category has a clear boundary, which is mutually exclusive and does not overlap
- Concise and limited classification steps can quickly classify a requirement.
The greatest significance of this development model lies in:
The classification criteria for the data to be collected as components are established - clear and direct.
It is clear that it is possible to classify and match program execution:
Input a data and automatically match the corresponding type of components by inferring the type.