alibaba / x-render

🚴‍♀️ 阿里 - 很易用的中后台「表单 / 表格 / 图表」解决方案
https://xrender.fun
7.04k stars 995 forks source link

[BUG]onValidate函数默认空函数?那getValidateList还是会执行,耗费性能! #579

Closed YangsonHung closed 3 years ago

YangsonHung commented 3 years ago

1.依赖仓库的版本(Dependencies versions)

2.问题描述(Bug description): 由于需要实现自己的业务逻辑,我在业务里实现onChange时返回校验信息,复制了官方的getValidateList函数,做了些修改。当时我发现,我没有传onValidate属性,内部还是执行了getValidateList这个函数,原因在于onValidate默认是个空参数空函数体函数,依然执行。导致项目中即执行了我的根据业务修改了的getValidateList,又执行了源代码里的getValidateList,代码重复执行了2次,在页面表单数据量大时,页面编辑会很卡顿。我想问问为什么,内部的onValidate是直接执行的,他不是非必传属性吗?

3.最小复现demo(Reproduction demo)

我的业务组件封装:

<FormRender
    key={updateKey}
    className={styles.fr}
    widgets={widgets}
    mapping={mapping}
    propsSchema={propsSchema}
    formData={formData}
    onChange={e => {
        properties && hideBlanking(properties, e);

        onChange(e);
        onValidate(getValidateList(e, propsSchema));
    }}
    {...restProps}
/>

我修改的函数,我加了一个名为idxList 的数组,存放下标,用于标识array里面哪个没填

export const dealTypeValidate = (key, value, schema = {}, _formData) => {
    const idxList = [];
    const checkList = [];
    const { type, items } = schema;
    const obj = {
        value,
        schema,
    };

    if (type === 'object') {
        const { checkList: list } = getValidateList(value, schema, _formData); // eslint-disable-line

        checkList.push(...list);
    } else if (type === 'array') {
        value.forEach((v, index) => {
            const { checkList: list } = dealTypeValidate(key, v, items, _formData);

            list.length && idxList.push(index + 1);
            checkList.push(...list);
        });
    }
    if (getValidateText(obj)) {
        checkList.push(key);
    }
    return { checkList, idxList };
};
export const getValidateList = (val = {}, { properties, required } = {}, formData) => {
    const _formData = formData || val;
    const checkList = [];
    const idxList = [];
    // const { properties, required } = schema;

    // 校验必填(required 属性只在 type:object 下存在)
    if (required && required.length > 0) {
        required.forEach(key => {
            const schema = (properties && properties[key]) || {};
            const hidden = keyHidden(schema, val);
            const _hidden = convertValue(hidden, _formData, val);
            const itemValue = val && val[key];

            if (isEmptyValue(itemValue, schema) && !_hidden) {
                checkList.push(key);
            }
        });
    }

    if (properties && val && Object.keys(val) && Object.keys(val).length > 0) {
        Object.keys(val).forEach(key => {
            const value = val[key];
            const schema = properties[key] || {};
            const hidden = keyHidden(schema, val);
            const _hidden = convertValue(hidden, _formData, val);

            if (!_hidden) {
                const { checkList: list, idxList: indexList } = dealTypeValidate(key, value, schema, _formData);

                idxList.push(...indexList);
                checkList.push(...list);
            }
        });
    }

    return { checkList, idxList };
};

官方源码里的handlechange函数直接执行了onValidate

  // 用户输入都是调用这个函数
  const handleChange = (key, val) => {
    isUserInput.current = true;
    // 开始编辑,节流
    setEditing(true);
    debouncedSetEditing(false);
    onChange(val);
    onValidate(getValidateList(val, schema));
  };

现在的问题是getValidateList这个函数被执行了2次,一个是我修改的,一个是官方源码里的。貌似我无法通过组件传值阻止他源码里的执行。这样我只能将源码都复制过来自己构建,然后在那行代码加判断了。

FateRiddle commented 3 years ago

form-render 0.x 版本确实在性能优化的不够,这些问题都在 form-render 1.x 中解决了哦。升级可以参加官方文档的迁移 https://x-render.gitee.io/form-render

同时,我们已经不对 0.x 版本进行维护了,望谅解。

youngjuning commented 3 weeks ago

form-render 1.x 也没有解决 Input 框输入卡顿的问题