7
头图

background

After working on adding, deleting, checking and modifying (node, mysql, serverless) for more than half a year, the business side was short of manpower, and the boss asked me to support other teams to write a few pages.

I haven't touched my hands for a long time, except for react vaguely remembered, antd basically can only watch the official demo and write line by line. There were some familiar problems in the middle, but unfortunately the previous experience was no longer useful.

Demo address: https://codesandbox.io/s/antd-about-resetfields-tjcns

These questions have been mentioned repeatedly in the issue 161c530c11debb of the warehouse of . Read the following, including but not limited to the following questions, will get the answer:
20211221224910

To summarize:

  • Form form, React hooks component, initialValues when initializing data, the second time, third time...pass the new value, the form is not updated, always display the first data?
  • The new form of the pop-up layer does not work to reset the value?

    • Modal uses destroyOnClose, there is Form in it, and form.resetFields is used, why does it fail?
    • The initialValues in Modal has been updated. Form.resetFields is used. Does it take effect after opening it twice?

Have something to say

The language description seems too pale, so just look at the animated picture:
reset-small

This is a simple add, delete, check and modify page. The new and edit share the same component. It is expected that the form will be re-rendered according to the initialValues after the open pop-up edit form is closed and reopened, but the result is the second time Open, the edit box is not refreshed.

The pseudo code implemented is roughly as follows:

import React, { useEffect } from "react";
import { Modal, Form, Input, Button, Checkbox } from "antd";

export function EditModal(props) {
  const { visible, onOk, onCancel, content = {} } = props;
  const [form] = Form.useForm();
  const isEdit = !!content.sort;
  const handlSubmit = (close) => {
    // 一些提交逻辑
  };
  useEffect(() => {
    // setTimeout(() => {
    form.resetFields();
    // });
  }, [content]);

  return (
    <Modal
      title={`${isEdit ? "编辑" : "新建"}备注`}
      visible={visible}
      destroyOnClose
      onOk={onOk}
      onCancel={onCancel}
    >
      <Form
        name="basic"
        labelCol={{ span: 7 }}
        wrapperCol={{ span: 14 }}
        form={form}
        initialValues={content}
        autoComplete="off"
      >
        {...一些表单}
      </Form>
    </Modal>
  );
}

I believe that most of the friends who have problems are just like me, and the code above is implemented like this.

Analyze specific issues

Let me give a conclusion first, the reasons for the above problems are mainly caused by three problems:

  • The posture of react hooks is incorrect. The antd4 form introduces hooks, which is different from the use of antd3;
  • Unclear understanding of the initialValues of the form form;
  • The rendering of Modal child elements is asynchronous, destroyOnClose is used incorrectly;

When initialValues initializes the data, the second, third...pass the new value, the form is not updated?

Because initialValues is only valid when the form is initialized for the first time, as long as the form is not uninstalled and remounted, changing the initialValues will not refresh the value of the form. The original design of the form is like this; the following is the complete implementation of initialValues initialized and stored in the store:

  this.setInitialValues = function (initialValues, init) {
    _this.initialValues = initialValues || {};
    if (init) {
      // setValues 作用类似于Object.assign();
      _this.store = setValues({}, initialValues, _this.store);
    }
  };

This.store is stored in the form instance, as long as the instance is not destroyed, the value of store will not change.

destroyOnClose, resetting the value of the new form of the pop-up layer does not work?

First of all, there is a concept. InitialValues is stored in the form instance generated by hooks when the Form instance is mounted.

So when we use destroyOnClose, although the Modal and the Form in the Modal box are destroyed, the form instance still exists. This hook instance is mounted on the EditModal element and is not destroyed together, so when the pop-up window opens again, The form will be rendered again according to the store of this form (see above for reasons).

Modal uses destroyOnClose, there is Form in it, and form.resetFields is used, why does it fail?

When we realize that the form instance has not been destroyed and may have saved the last form editing state, we will think of using the useEffect hook to observe the initial value and use form.resetFields to reset the instance, but finally found that this did not work ( I also stepped on this pit).

When I removed destroyOnClose, I found that it took effect. Later I went to look at the implementation source code of form.resetFields:

this.resetFields = function (nameList) {
  var prevStore = _this.store;

  if (!nameList) {
    // console.log(JSON.stringify(prevStore), JSON.stringify(_this.initialValues));
    _this.store = setValues({}, _this.initialValues);
    _this.resetWithFieldInitialValue();
    _this.notifyObservers(prevStore, null, {
      type: 'reset'
    });
    return;
  }
}

This implementation is as simple and straightforward as initialValues, so the problem is not with resetFields. The problem lies in Modal. Simply put, the creation of Moda has an asynchronous process, so the rendering of sub-components is not synchronous. The normal component rendering is as follows:

20211223222510

Just like me above, add a sentence to the resetFields console, and you will find that _this.initialValues is the initial value of the last time, not the new one (because the Form element has not yet been mounted), so resetFields is adjusted here. .

There is also a simple way to prove that the sub-component mounting of the Modal component is asynchronous, which is to play as follows:

useEffect(() => {
  setTimeout(() => {
    form.resetFields();
  });
}, [content]);

With this implementation, you will find that resetFields actually takes effect, because after a macro task, the Form element has been mounted.

So here is telling us to use destroyOnClose as little as possible, because the rendering of Modal is time-consuming and laborious.

Modal is initialized with form.resetFields, does it take effect after opening it twice in a row?

I believe that after a series of explanations above, you already have the answer in your mind; destroyOnClose is indeed not suitable for writing forms in Modal.

So, is the correct posture of Form initalValues reset in Modal?

careful

learn from mistakes

After this experience, I remembered:

  • Use destroyOnClose with caution, because Modal rendering is expensive;
  • Hooks are a good thing, but you have to use it right;
  • Antd is a good thing, provided that you can use it;
  • I'm still too dished;

Welcome to follow my front-end public : 161c530c11e613 Front-end black hole


前端黑洞
3.5k 声望4.7k 粉丝

不要假装很努力,因为结果不会陪你演戏