DouyinFE / semi-design

🚀A modern, comprehensive, flexible design system and React UI library. 🎨 Provide more than 3000+ Design Tokens, easy to build your design system. Make Semi Design to Any Design. 🧑🏻‍💻 Design to Code in one click
https://semi.design
Other
8.43k stars 711 forks source link

[BUG] <FormApi.validate['xx1', 'xx2']在xx2的validate下调用了formApi.validate(['xx1']),那么formApi.validate(['xx1', 'xx2'])一直不会resolve> #2317

Closed wangming27 closed 4 months ago

wangming27 commented 4 months ago

Is there an existing issue for this?

Which Component

Form

Semi Version

2.60.0

Current Behavior

export const handleAsyncCallback = (callback: () => void) => {
  callback();
};
export default () => {
  const formApiRef = useRef<FormApi>();
  const submit = async () => {
    console.log('submit start');
    try {
      await formApiRef.current?.validate?.(['name1', 'name2']);
    } catch (err) {
      console.log('err', err);
    }

    console.log('submit end');
  };

  console.log('render');

  return (
    <>
      <Form
        getFormApi={formApi => (formApiRef.current = formApi)}
        labelAlign="left"
        labelPosition="left"
      >
        <Form.Input
          placeholder="请输入名称"
          field="name1"
          rules={[{ required: true }]}
        />
        <Form.Input
          placeholder="请输入名称"
          field="name2"
          // rules={[{ required: true, message: 'name不能为空' }]}
          validate={val =>
            new Promise(resolve => {
              if (val !== 'name') {
                resolve('name值不对');
                return;
              }
              handleAsyncCallback(async () => {
                await formApiRef.current?.validate(['name1']);
                console.log('hh');
                resolve('');
                console.log('hh end');
              });
            })
          }
        />
      </Form>
      <Button onClick={submit}>提交</Button>
    </>
  );
};

上面点提交后不会走到 console.log('submit end');

Expected Behavior

预期如之前版本一样,可以支持这种写法

Steps To Reproduce

按上面代码执行

ReproducibleCode

export const handleAsyncCallback = (callback: () => void) => {
  callback();
};
export default () => {
  const formApiRef = useRef<FormApi>();
  const submit = async () => {
    console.log('submit start');
    try {
      await formApiRef.current?.validate?.(['name1', 'name2']);
    } catch (err) {
      console.log('err', err);
    }

    console.log('submit end');
  };

  console.log('render');

  return (
    <>
      <Form
        getFormApi={formApi => (formApiRef.current = formApi)}
        labelAlign="left"
        labelPosition="left"
      >
        <Form.Input
          placeholder="请输入名称"
          field="name1"
          rules={[{ required: true }]}
        />
        <Form.Input
          placeholder="请输入名称"
          field="name2"
          // rules={[{ required: true, message: 'name不能为空' }]}
          validate={val =>
            new Promise(resolve => {
              if (val !== 'name') {
                resolve('name值不对');
                return;
              }
              handleAsyncCallback(async () => {
                await formApiRef.current?.validate(['name1']);
                console.log('hh');
                resolve('');
                console.log('hh end');
              });
            })
          }
        />
      </Form>
      <Button onClick={submit}>提交</Button>
    </>
  );
};

Environment

- OS:
- browser:

Anything else?

image 这里判断的问题: 在我的例子里,第一次validate('name1', 'name2')【定为promise.all-1】后,name2表单项又执行了validate('name1')【定为promise.all-2】。 最终的执行结果:

  1. promise.all-1的name1的promise会先执行其回调,但是比较后 validatePromise.current !== rootPromise 不相等。为啥呢,因为被promise.all-2的name1给覆盖掉了。比较时的validatePromise.current实际上是promise.all-2的name1;

  2. 上面逻辑不像等后直接return了,所以promise.all-1 会一直pending

  3. 业务代码里要交接promise.all-1 的程序控制权,因为一直pending,所以点了提交没反应

pointhalo commented 4 months ago

竞态验证下,前面触发的要被丢弃。这是符合预期的。不是bug。 image