记录一次排查 antd 组件的 bug

背景

一个页面里写了一个 Form 表单,Form 中有一个穿梭框以及一些其他组件,进入页面时穿梭框外面包裹一层 Spin 组件 loading 状态,等穿梭框里的值发送的请求结果接收后 loading 取消,最下面有个 button 来调用 Form 的 onFinish 方法

大概长这样

代码缩略如下

tsx 复制代码
import { useState } from 'react'
import { Button, Form, Spin, Transfer } from 'antd'
import { useMount } from 'ahooks'

const profile = () => {
  const [loading, setLoading] = useState(true)
  const [msg, setMsg] = useState('尚未提交')
  const [targetKeys, setTargetKeys] = useState<string[]>([])
  const [mockData, setMockData] = useState([
    { title: '123', key: 'a' },
    { title: '456', key: 'b' },
    { title: '789', key: 'c' }
  ])

  useMount(() => {
    setTimeout(() => {
      setLoading(false)
    }, 2000)
  })

  const handleChange = (newTargetKeys: string[]) => {
    setTargetKeys(newTargetKeys)
  }

  const click = () => {
    setMsg('提交成功')
  }

  return (
    <>
      <Form onFinish={click}>
        <Form.Item name="val" rules={[{ required: true, message: '请选择' }]}>
          <Spin spinning={loading}>
            <Transfer
              showSearch
              dataSource={mockData}
              targetKeys={targetKeys}
              onChange={handleChange}
              render={item => item.title}
            />
          </Spin>
        </Form.Item>
        <Button htmlType="submit">提交</Button>
        <div>{msg}</div>
      </Form>
    </>
  )
}

export default profile

为穿梭框设置rule位required,即提交时为必选,没有值会报错

每次进入页面时用settimout模拟请求接口两秒后取消loading

报错

此时我们把值传到右边,点击button提交,发现明明穿梭框这里是有值的,还会给我们报错提示

把所有的值全都传过来,点击button依旧是报错

此时我是百思不得其解,明明此时的穿梭框是拿到值的,这里去打印一下targetKey也是拿到了值的,为什么还会给我报错呢

解决?

此时我就开始想了,应该是 antd 组件的 bug,这里的穿梭框组件有搜索框,所以实际上是两个组件,搜索框和穿梭框的组合组件,而Form 校验的时候也会把搜索框的值进行校验,此时我们只选择了穿梭框的值 但是搜索框是没有值的,所以这里会有一个报错提醒。

这么一顿思考完,我真是个天才,这种bug都能让我想通。然后就去想了下解决方案,把穿梭框从 Form 中拿出来,在点击 button 的时候判断下,穿梭框有值就正常进行,没值的时候在下面写一个相同样式的文字提示。

真正的问题所在

这么想完,这不直接搞定了,但是组里的其他大佬一眼就发现了端倪。

这里根本的问题是,被Form.Item包裹的组件会被自动的添加value属性和onChange方法,数据被Form来接管,此处可以看antd文档

而我们这里被Form.Item所包裹的第一层组件是一个Spin,它并没有对应的value和onChange,所以Form这里所劫持的数据并不是穿梭框里值,根本就取不到值,所以这就解释了为什么我们明明把值传过去了却点击button时还是会有提示警告。

而解决方案非常简单,只需要把Spin组件包裹在Form.Item外面,让Form.Item直接拿到穿梭框的value和onChange,此时我们再去点击button,就不会有报错提示了,可以看到点击后的文字显示未提交成功。

总结

可能有些大佬或者之前了解的会觉得非常简单的一个事,但是对于不了解这个问题的小白来讲是很难解决的一个问题,这个排查过程也非常有收获,本文主要在于记录一下整个过程,以及向还不清楚的人普及一下

本文同步发在个人网站

欢迎指正

相关推荐
多多*25 分钟前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong29 分钟前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10151 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.31 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10151 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中2 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
Yvonne爱编码2 小时前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder
SuperherRo2 小时前
Web开发-JavaEE应用&SpringBoot栈&SnakeYaml反序列化链&JAR&WAR&构建打包
前端·java-ee·jar·反序列化·war·snakeyaml
大帅不是我2 小时前
Python多进程编程执行任务
java·前端·python
前端怎么个事2 小时前
框架的源码理解——V3中的ref和reactive
前端·javascript·vue.js