记录一次排查 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,就不会有报错提示了,可以看到点击后的文字显示未提交成功。

总结

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

本文同步发在个人网站

欢迎指正

相关推荐
小李小李不讲道理1 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻1 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
mapbar_front2 小时前
在职场生存中如何做个不好惹的人
前端
牧杉-惊蛰2 小时前
纯flex布局来写瀑布流
前端·javascript·css
一袋米扛几楼983 小时前
【软件安全】什么是XSS(Cross-Site Scripting,跨站脚本)?
前端·安全·xss
向上的车轮3 小时前
Actix Web适合什么类型的Web应用?可以部署 Java 或 .NET 的应用程序?
java·前端·rust·.net
XiaoYu20024 小时前
第1章 核心竞争力和职业规划
前端·面试·程序员
excel4 小时前
🧩 深入浅出讲解:analyzeScriptBindings —— Vue 如何分析 <script> 里的变量绑定
前端
蓝瑟4 小时前
AI时代程序员如何高效提问与开发工作?
前端·ai编程
林晓lx4 小时前
使用Git钩子+ husky + lint语法检查提高前端项目代码质量
前端·git·gitlab·源代码管理