React 最佳實踐:動態表單| 8月更文挑戰

具體場景

基於 Ant Design, 咱們來實現一個【薪資調查表】,需求有二:html

  • 職位(Job)列表 模擬從服務端拉取 form-2.pngreact

  • 當職位是 Student 時,薪資(Income) 輸入框消失。 form-3.pngweb

    form-4.png

實現

UI 描述

form-1.png

咱們先用 Ant Design 提供的 Form, Input, Select, Button 組件來構建 UI 架構。數組

  • labelCollabel 標籤佈局,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

useState

const [state, setState] = useState(initialState);
複製代碼

它會返回一個 state,以及更新 state 的函數。框架

initialState 會做爲 state 的初始值。函數

useEffect

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;
複製代碼

React 最佳實踐

相關文章
相關標籤/搜索