解决:Warning: Instance created by useForm is not connect to any Form element.

4,915 阅读1分钟

问题描述

Ant Design组件库 Modal组件里面使用Form组件的时候,遇到如下图错误

image.png

github.com 上有很多对这个问题的描述。比如

问题原因

Ant Design在Modal中使用Form表单,并且通过Form.useForm()获取form对象将其挂载到指定的Form表单后仍会出现警告,是由于Ant Design的Modal组件会在Form表单之前创建,因此当页面初始化时form对象会找不到可关联的Form表单,于是出现上述警告。

解决方案

找到问题的原因之后,就明白如何解决了,在useEffect 添加props.visible,根据一定的依赖条件来触发的副作用。

1.useEffect 添加props.visible 根据一定的依赖条件来触发的副作用 2.Modal 添加forceRender

代码


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

const UserModel = (props: any) => {
  const [form] = Form.useForm();
  const [confirmLoading, setConfirmLoading] = React.useState(false);

  let formData = {
    name: "",
    age: "",
    address: "",
    ...props.userInfo
  }
  //添加props.visible 根据一定的依赖条件来触发的副作用
  useEffect(() => {
    formData = {
      ...formData,
      ...props.userInfo
    }
    form.setFieldsValue(formData);
  }, [props.visible]);


  // form.setFieldsValue(formData)

  // 确定
  const handleOk = () => {
    // TODO:form表单
    props.onOk()
  }

  const handleOnSubmit = () => {

  }

  // 取消
  const handleCancel = () => {
    props.onCancel()
  }

  const onFinish = (values: any) => {
    console.log(values);
    setConfirmLoading(true)
    setTimeout(() => {
      props.onOk(values)
      setConfirmLoading(false)
    })
  }

  const onFinishFailed = () => {
    // props.onFinish()
  }
  
//添加 forceRender 
  return (
    <Modal
      forceRender
      title="Title"
      visible={props.visible}
      onOk={handleOk}
      confirmLoading={confirmLoading}
      onCancel={handleCancel}
      //去掉底部
      footer={[]}
    >
      <Form
        name="basic"
        form={form}
        labelCol={{ span: 8 }}
        wrapperCol={{ span: 16 }}
        initialValues={formData}
        onFinish={onFinish}
        onFinishFailed={onFinishFailed}
      >
        <Form.Item
          label="name"
          name="name"
          rules={[{ required: true, message: 'Please input your username!' }]}
        >
          <Input />
        </Form.Item>

        <Form.Item
          label="age"
          name="age"
          rules={[{ required: true, message: 'Please input your age!' }]}
        >
          <Input />
        </Form.Item>

        <Form.Item
          label="address"
          name="address"
          rules={[{ required: true, message: 'Please input your age!' }]}
        >
          <Input />
        </Form.Item>

        <Form.Item name="remember" valuePropName="checked" wrapperCol={{ offset: 8, span: 16 }}>
          <Checkbox>Remember me</Checkbox>
        </Form.Item>

        <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
          <Button type="primary" htmlType="submit">
            Submit
          </Button>
        </Form.Item>
      </Form>
    </Modal>
  )
}

export default UserModel;

最后

如果有问题或者有更好的方式,欢迎留言,

补充:2021年07月12日

在查阅Ant Design文档中demo的时候,发现了官方有Modal中嵌套Form表单的Demo

官方文档地址,这里贴出来代码:

// reset form fields when modal is form, closed
const useResetFormOnCloseModal = ({ form, visible }) => {
  const prevVisibleRef = useRef();
  useEffect(() => {
    prevVisibleRef.current = visible;
  }, [visible]);
  const prevVisible = prevVisibleRef.current;
  useEffect(() => {
    if (!visible && prevVisible) {
      form.resetFields();
    }
  }, [visible]);
};

const ModalForm = ({ visible, onCancel }) => {
  const [form] = Form.useForm();
  useResetFormOnCloseModal({
    form,
    visible,
  });

  const onOk = () => {
    form.submit();
  };

  return (
    <Modal title="Basic Drawer" visible={visible} onOk={onOk} onCancel={onCancel}>
      <Form form={form} layout="vertical" name="userForm">
        <Form.Item
          name="name"
          label="User Name"
          rules={[
            {
              required: true,
            },
          ]}
        >
          <Input />
        </Form.Item>
        <Form.Item
          name="age"
          label="User Age"
          rules={[
            {
              required: true,
            },
          ]}
        >
          <InputNumber />
        </Form.Item>
      </Form>
    </Modal>
  );
};