mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 14:13:37 +08:00
fix: Upload in React 18 sync problem (#36968)
* fix: sync flush * test: test case * test: fix deps
This commit is contained in:
parent
74d76038ad
commit
ad312b23a2
@ -3,6 +3,7 @@ import type { UploadProps as RcUploadProps } from 'rc-upload';
|
|||||||
import RcUpload from 'rc-upload';
|
import RcUpload from 'rc-upload';
|
||||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { flushSync } from 'react-dom';
|
||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
import DisabledContext from '../config-provider/DisabledContext';
|
import DisabledContext from '../config-provider/DisabledContext';
|
||||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||||
@ -101,7 +102,11 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
|
|||||||
cloneList = cloneList.slice(0, maxCount);
|
cloneList = cloneList.slice(0, maxCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
setMergedFileList(cloneList);
|
// Prevent React18 auto batch since input[upload] trigger process at same time
|
||||||
|
// which makes fileList closure problem
|
||||||
|
flushSync(() => {
|
||||||
|
setMergedFileList(cloneList);
|
||||||
|
});
|
||||||
|
|
||||||
const changeInfo: UploadChangeParam<UploadFile> = {
|
const changeInfo: UploadChangeParam<UploadFile> = {
|
||||||
file: file as UploadFile,
|
file: file as UploadFile,
|
||||||
|
@ -914,7 +914,7 @@ describe('Upload', () => {
|
|||||||
throw new TypeError("Object doesn't support this action");
|
throw new TypeError("Object doesn't support this action");
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.spyOn(global, 'File').mockImplementationOnce(fileConstructor);
|
const spyIE = jest.spyOn(global, 'File').mockImplementationOnce(fileConstructor);
|
||||||
fireEvent.change(container.querySelector('input'), {
|
fireEvent.change(container.querySelector('input'), {
|
||||||
target: {
|
target: {
|
||||||
files: [{ file: 'foo.png' }],
|
files: [{ file: 'foo.png' }],
|
||||||
@ -925,6 +925,7 @@ describe('Upload', () => {
|
|||||||
await sleep();
|
await sleep();
|
||||||
|
|
||||||
expect(onChange.mock.calls[0][0].fileList).toHaveLength(1);
|
expect(onChange.mock.calls[0][0].fileList).toHaveLength(1);
|
||||||
|
spyIE.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/ant-design/ant-design/issues/33819
|
// https://github.com/ant-design/ant-design/issues/33819
|
||||||
@ -965,4 +966,58 @@ describe('Upload', () => {
|
|||||||
const { container: wrapper2 } = render(<Upload prefixCls="custom-upload" />);
|
const { container: wrapper2 } = render(<Upload prefixCls="custom-upload" />);
|
||||||
expect(wrapper2.querySelectorAll('.custom-upload-list').length).toBeGreaterThan(0);
|
expect(wrapper2.querySelectorAll('.custom-upload-list').length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://github.com/ant-design/ant-design/issues/36869
|
||||||
|
it('Prevent auto batch', async () => {
|
||||||
|
const mockFile1 = new File(['bamboo'], 'bamboo.png', {
|
||||||
|
type: 'image/png',
|
||||||
|
});
|
||||||
|
const mockFile2 = new File(['light'], 'light.png', {
|
||||||
|
type: 'image/png',
|
||||||
|
});
|
||||||
|
|
||||||
|
let info1;
|
||||||
|
let info2;
|
||||||
|
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const { container } = render(
|
||||||
|
<Upload
|
||||||
|
customRequest={info => {
|
||||||
|
if (info.file === mockFile1) {
|
||||||
|
info1 = info;
|
||||||
|
} else {
|
||||||
|
info2 = info;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onChange={onChange}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.change(container.querySelector('input'), {
|
||||||
|
target: {
|
||||||
|
files: [mockFile1, mockFile2],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// React 18 is async now
|
||||||
|
await act(async () => {
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
onChange.mockReset();
|
||||||
|
|
||||||
|
// Processing
|
||||||
|
act(() => {
|
||||||
|
info1.onProgress({ percent: 10 }, mockFile1);
|
||||||
|
info2.onProgress({ percent: 20 }, mockFile2);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
fileList: [
|
||||||
|
expect.objectContaining({ percent: 10 }),
|
||||||
|
expect.objectContaining({ percent: 20 }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user