Browse Source

fix: Upload in React 18 sync problem (#41082)

* fix: Upload in React 18 sync problem

* test: add test case
pull/41085/head
lijianan 2 years ago
committed by GitHub
parent
commit
c38108a63c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      components/upload/Upload.tsx
  2. 49
      components/upload/__tests__/upload.test.tsx
  3. 0
      components/upload/utils.ts

4
components/upload/Upload.tsx

@ -116,7 +116,9 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
changeInfo.event = event;
}
onChange?.(changeInfo);
flushSync(() => {
onChange?.(changeInfo);
});
};
const mergedBeforeUpload = async (file: RcFile, fileListArgs: RcFile[]) => {

49
components/upload/__tests__/upload.test.tsx

@ -7,7 +7,7 @@ import type { RcFile, UploadFile, UploadProps } from '..';
import Upload from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, waitFakeTimer, act } from '../../../tests/utils';
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import Form from '../../form';
import { resetWarned } from '../../_util/warning';
import { getFileItem, isImageUrl, removeFileItem } from '../utils';
@ -946,4 +946,51 @@ describe('Upload', () => {
}),
);
});
it('prevent auto batch in control mode', async () => {
const mockFile1 = new File(['bamboo'], 'bamboo.png', { type: 'image/png' });
const mockFile2 = new File(['light'], 'light.png', { type: 'image/png' });
const customRequest = jest.fn(async (options) => {
// stop here to make sure new fileList has been set and passed to Upload
// eslint-disable-next-line no-promise-executor-return
await new Promise((resolve) => setTimeout(resolve, 0));
options.onProgress({ percent: 0 });
const url = Promise.resolve<string>('https://ant.design');
options.onProgress({ percent: 100 });
options.onSuccess({}, { ...options.file, url });
});
let fileListOut: UploadProps['fileList'] = [];
const Demo: React.FC = () => {
const [fileList, setFileList] = React.useState<UploadFile[]>([]);
const onChange: UploadProps['onChange'] = async (e) => {
const newFileList = Array.isArray(e) ? e : e.fileList;
setFileList(newFileList);
fileListOut = newFileList;
};
return (
<Upload customRequest={customRequest} onChange={onChange} fileList={fileList}>
<button type="button">Upload</button>
</Upload>
);
};
const { container } = render(<Demo />);
fireEvent.change(container.querySelector<HTMLInputElement>('input')!, {
target: { files: [mockFile1, mockFile2] },
});
// React 18 is async now
await waitFakeTimer();
fileListOut.forEach((file) => {
expect(file.status).toBe('done');
});
});
});

0
components/upload/utils.tsx → components/upload/utils.ts

Loading…
Cancel
Save