前端杂记 -- AntD Form onFieldsChange不触发

1,450 阅读2分钟

问题发现

最近在做复杂的表单需求,我们决定基于AntD的Form做开发,其中有一个需求需要用到onFieldsChange,可是实际使用的时候发现,虽然设置了onFieldsChange,但是并没有触发。

寻找根因

调试antd

我知道可以先把第三方库git clone到本地,然后通过npm link就可以链接第三方库进行调试了,但是实际上,link的时候要注意几个问题

  • 把antd和rc-field-form(antd的form实际上基于rc-field-form) clone到本地,并且在各自的目录下执行npm install && npm link
  • antd的less文件解析,我们项目用的是sass,并没有解析less的配置,因此需要在webpack中加上配置
  1. 找到antd中全部的less文件 这里我用到了一个文件,得到了全部的less文件路径
function walkSync(currentDirPath, callback) {
  var fs = require('fs'),
      path = require('path');
  fs.readdirSync(currentDirPath).forEach(function (name) {
      var filePath = path.join(currentDirPath, name);
      var stat = fs.statSync(filePath);
      if (stat.isFile()) {
        stat.name
          callback(filePath, stat);
      } else if (stat.isDirectory()) {
          walkSync(filePath, callback);
      }
  });
}

walkSync(path.resolve('~/ant-design/components'), (filePath, stat) => {
  if (~filePath.indexOf('.less')) {
    console.log(filePath);
  }
})

通过以上脚本,我得到了全部less文件的路径

image.png

  1. webpack修改:添加文件入口 entry: [ ..., ...LESS_DIR, ],

  2. webpack修改:新增less-loader

          test: /\.less$/i,
          use: [
             'style-loader',
             'css-loader',
            {
              loader: 'less-loader',
              options: {
                sourceMap: false,
                lessOptions: {
                  paths: LESS_DIR,
                },
              },
            },
            'postcss-loader'
          ],
        },
  • 把antd和rc-field-form的依赖添加到webpack依赖中
        ...,
      modules: [..., ANTD_DIR, RC_FIELD_FORM_DIR],
    },
  • 在antd的目录中执行npm link rc-field-form
  • 在项目目录中执行npm link antd 然后就可以开始调试找问题啦

源码分析

rc-fields-form/src/Form.tsx 这里可以看到,传入的onFieldsChange是被设置到callbacks这个对象中了

image.png

那么callbacks这个对象是放在哪里的呢?是放在formInstance上的,那么问题很明显了,原因就是form实例上的callbacks被重置了,那么为什么被重置呢?

image.png

结果很囧,就是因为我们在两个子组件中都用了Form组件,但是两个组件公用一个form实例,导致后一个Form组件的onFieldsChange覆盖了前一个Form组件的onFieldsChange

结论

虽然通过Form组件设置onFieldsChange,但该回调函数实为挂载在form实例上

如果两个Form组件同时应用一个form实例,后挂载的Component2的onFieldsChange会覆盖Component1组件的onFieldsChange,导致Component1的onFieldsChange不生效

相关资料

issue

复现demo