问题发现
最近在做复杂的表单需求,我们决定基于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中加上配置
- 找到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文件的路径
-
webpack修改:添加文件入口
entry: [ ..., ...LESS_DIR, ], -
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这个对象中了
那么callbacks这个对象是放在哪里的呢?是放在formInstance上的,那么问题很明显了,原因就是form实例上的callbacks被重置了,那么为什么被重置呢?
结果很囧,就是因为我们在两个子组件中都用了Form组件,但是两个组件公用一个form实例,导致后一个Form组件的onFieldsChange覆盖了前一个Form组件的onFieldsChange
结论
虽然通过Form组件设置onFieldsChange,但该回调函数实为挂载在form实例上
如果两个Form组件同时应用一个form实例,后挂载的Component2的onFieldsChange会覆盖Component1组件的onFieldsChange,导致Component1的onFieldsChange不生效