The scenario

Based on Ant Design, we will implement a salary questionnaire with two requirements:

  • Job listEmulation pulls from the server

  • When the job isStudentWhen,IncomeThe input box disappears.

implementation

The UI description

We started with the Form, Input, Select, and Button components provided by Ant Design to build the UI architecture.

  • LabelCol sets the layout for the label label and wrapperCol sets the layout for the input control, using the same way as the Grid Grid.

  • Call the Web native submission logic with .

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;
Copy the code

Now that the basic UI framework is complete, let’s implement the first two logical requirements.

Emulated server pull list

Use Estate and useEffect Hooks:

useState

const [state, setState] = useState(initialState);
Copy the code

It returns a state and a function to update the state.

InitialState will be the initial value of state.

useEffect

useEffect(didUpdate);
Copy the code

The Hook receives a function that contains imperative code that may have side effects.

The function assigned to useEffect is executed after the component is rendered to the screen. Changing the DOM, adding subscriptions, setting timers, logging, and performing other side effects can be performed in useEffect.

Resources created by Effect, such as subscriptions or timer ids, need to be cleared when the component uninstalls. To do this, the useEffect function returns a cleanup function, which we will also use below.

By default, effect is executed after each round of component rendering is complete. However, what if we only want to execute effect under certain conditions?

To do this, you can pass a second parameter to useEffect, and the subscription will be recreated only if the props. Source changes.

useEffect(didiUpdate, [props.source]);
Copy the code

implementation

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); }; } []);// [], run this command only once

  return;
};
Copy the code

After the list data is pulled, iterate through the Jobs render dropdown:

<Select>
  {jobs.length > 0 ? (
    jobs.map((job) = > (
      <Option key={job} value={job}>
        {job}
      </Option>))) : (<Option>loading</Option>
  )}
</Select>
Copy the code

Dynamic form elements

When the Job field is Student, the Income input box needs to be hidden. In this case, we need to get the value of the Job field.

In the function component, you interact with the Form data field via form.useform. The getFieldValue method gets the value of the corresponding field name.

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>
};
Copy the code

We want to update the explicit and implicit of the Income input control after changing the Job field value. ShouldUpdate can help us implement this update logic.

<Form.Item
  shouldUpdate={(prevValues, currentValues) = >prevValues.job ! == currentValues.job } ></Form.Item>Copy the code

< form. Item name=”field” /> binds the Form function only to its immediate children, like this:

<Form.Item label="Field" name="field">
  <Input />
</Form.Item>
Copy the code

So we need to make the outer form. Item a pure style-free binding component by adding noStyle.

implementation

<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>
Copy the code

Dynamic form complete code

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;
Copy the code

React Best Practices

  • React Best practice: Create a drag-and-drop list by hand
  • React Best Practice: Integrating third-party Libraries (d3.js)
  • React Best Practices: How to Implement Native Portals
  • React best practice: Drag-and-drop sidebar
  • React best practice: Implement step-by-step operations based on routes
  • React best practice: Work with multiple data sources
  • React best practice: Complete a list of requirements
  • React best practice: Dynamic forms