Skip to content

Commit 8e3d74a

Browse files
authored
fix(content-uploader): use refs for items and itemIds (#3785)
* fix(upload): use refs for items and itemIds * fix(upload): use refs for items and itemIds * fix(upload): use refs for items and itemIds * fix(upload): use refs for items and itemIds
1 parent ecf0f72 commit 8e3d74a

File tree

2 files changed

+86
-67
lines changed

2 files changed

+86
-67
lines changed

src/elements/content-uploader/ContentUploader.tsx

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
130130

131131
itemsRef: React.MutableRefObject<UploadItem[]>;
132132

133+
itemIdsRef: React.MutableRefObject<Object>;
134+
133135
static defaultProps = {
134136
apiHost: DEFAULT_HOSTNAME_API,
135137
chunked: true,
@@ -182,6 +184,9 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
182184

183185
this.itemsRef = React.createRef();
184186
this.itemsRef.current = [];
187+
188+
this.itemIdsRef = React.createRef();
189+
this.itemIdsRef.current = {};
185190
}
186191

187192
/**
@@ -289,9 +294,8 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
289294
*/
290295
getNewFiles = (files: Array<UploadFileWithAPIOptions | File>): Array<UploadFileWithAPIOptions | File> => {
291296
const { rootFolderId } = this.props;
292-
const { itemIds } = this.state;
293297

294-
return Array.from(files).filter(file => !itemIds[getFileId(file, rootFolderId)]);
298+
return Array.from(files).filter(file => !this.itemIdsRef.current[getFileId(file, rootFolderId)]);
295299
};
296300

297301
/**
@@ -303,9 +307,8 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
303307
items: Array<DataTransferItem | UploadDataTransferItemWithAPIOptions>,
304308
): Array<DataTransferItem | UploadDataTransferItemWithAPIOptions> => {
305309
const { rootFolderId } = this.props;
306-
const { itemIds } = this.state;
307310

308-
return Array.from(items).filter(item => !itemIds[getDataTransferItemId(item, rootFolderId)]);
311+
return Array.from(items).filter(item => !this.itemIdsRef.current[getDataTransferItemId(item, rootFolderId)]);
309312
};
310313

311314
/**
@@ -342,26 +345,22 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
342345

343346
const firstFile = getFile(newFiles[0]);
344347

345-
this.setState(
346-
state => ({
347-
itemIds: {
348-
...state.itemIds,
349-
...newItemIds,
350-
},
351-
}),
352-
() => {
353-
onBeforeUpload(newFiles);
354-
if (firstFile.webkitRelativePath && !isRelativePathIgnored) {
355-
// webkitRelativePath should be ignored when the upload destination folder is known
356-
this.addFilesWithRelativePathToQueue(newFiles, itemUpdateCallback);
357-
} else {
358-
this.addFilesWithoutRelativePathToQueue(
359-
newFiles,
360-
isPrepopulateFilesEnabled ? this.upload : itemUpdateCallback,
361-
);
362-
}
363-
},
364-
);
348+
const newItemIdsState = { ...this.itemsRef.current, ...newItemIds };
349+
350+
this.itemIdsRef.current = newItemIdsState;
351+
352+
this.setState({ itemIds: newItemIdsState }, () => {
353+
onBeforeUpload(newFiles);
354+
if (firstFile.webkitRelativePath && !isRelativePathIgnored) {
355+
// webkitRelativePath should be ignored when the upload destination folder is known
356+
this.addFilesWithRelativePathToQueue(newFiles, itemUpdateCallback);
357+
} else {
358+
this.addFilesWithoutRelativePathToQueue(
359+
newFiles,
360+
isPrepopulateFilesEnabled ? this.upload : itemUpdateCallback,
361+
);
362+
}
363+
});
365364
};
366365

367366
/**
@@ -469,15 +468,14 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
469468
itemUpdateCallback: Function,
470469
): void => {
471470
const { rootFolderId } = this.props;
472-
const { itemIds } = this.state;
473471

474472
if (dataTransferItems.length === 0) {
475473
return;
476474
}
477475

478476
const newItems = this.getNewDataTransferItems(dataTransferItems);
479477
newItems.forEach(item => {
480-
itemIds[getDataTransferItemId(item, rootFolderId)] = true;
478+
this.itemIdsRef.current[getDataTransferItemId(item, rootFolderId)] = true;
481479
});
482480

483481
if (newItems.length === 0) {
@@ -581,7 +579,6 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
581579
files: Array<UploadFileWithAPIOptions | File>,
582580
itemUpdateCallback: Function,
583581
) => {
584-
const { itemIds } = this.state;
585582
const { rootFolderId } = this.props;
586583

587584
// Convert files from the file API to upload items
@@ -611,7 +608,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
611608
uploadItem.options = uploadAPIOptions;
612609
}
613610

614-
itemIds[getFileId(uploadItem, rootFolderId)] = true;
611+
this.itemIdsRef.current[getFileId(uploadItem, rootFolderId)] = true;
615612

616613
return uploadItem;
617614
});
@@ -621,7 +618,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
621618
}
622619

623620
this.setState({
624-
itemIds,
621+
itemIds: this.itemIdsRef.current,
625622
});
626623
this.addToQueue(newItems, itemUpdateCallback);
627624
};
@@ -664,8 +661,6 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
664661
}
665662
}
666663

667-
this.itemsRef.current = updatedItems;
668-
669664
this.updateViewAndCollection(updatedItems, () => {
670665
if (itemUpdateCallback) {
671666
itemUpdateCallback();
@@ -727,19 +722,21 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
727722
*/
728723
removeFileFromUploadQueue = (item: UploadItem) => {
729724
const { onCancel, useUploadsManager } = this.props;
730-
const { items } = this.state;
731725
// Clear any error errorCode in footer
732726
this.setState({ errorCode: '' });
733727

734728
const { api } = item;
735729
api.cancel();
736730

737-
items.splice(items.indexOf(item), 1);
731+
const itemIndex = this.itemsRef.current.indexOf(item);
732+
const updatedItems = this.itemsRef.current
733+
.slice(0, itemIndex)
734+
.concat(this.itemsRef.current.slice(itemIndex + 1));
738735

739736
onCancel([item]);
740-
this.updateViewAndCollection(items, () => {
737+
this.updateViewAndCollection(updatedItems, () => {
741738
// Minimize uploads manager if there are no more items
742-
if (useUploadsManager && !items.length) {
739+
if (useUploadsManager && !updatedItems.length) {
743740
this.minimizeUploadsManager();
744741
}
745742

@@ -757,8 +754,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
757754
* @return {void}
758755
*/
759756
cancel = () => {
760-
const { items } = this.state;
761-
items.forEach(uploadItem => {
757+
this.itemsRef.current.forEach(uploadItem => {
762758
const { api, status } = uploadItem;
763759
if (status === STATUS_IN_PROGRESS) {
764760
api.cancel();
@@ -776,8 +772,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
776772
* @return {void}
777773
*/
778774
upload = () => {
779-
const { items } = this.state;
780-
items.forEach(uploadItem => {
775+
this.itemsRef.current.forEach(uploadItem => {
781776
if (uploadItem.status === STATUS_PENDING) {
782777
this.uploadFile(uploadItem);
783778
}
@@ -792,10 +787,9 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
792787
*/
793788
uploadFile(item: UploadItem) {
794789
const { overwrite, rootFolderId } = this.props;
795-
const { items } = this.state;
796790
const { api, file, options } = item;
797791

798-
const numItemsUploading = items.filter(item_t => item_t.status === STATUS_IN_PROGRESS).length;
792+
const numItemsUploading = this.itemsRef.current.filter(item_t => item_t.status === STATUS_IN_PROGRESS).length;
799793

800794
if (numItemsUploading >= UPLOAD_CONCURRENCY) {
801795
return;
@@ -812,11 +806,12 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
812806
};
813807

814808
item.status = STATUS_IN_PROGRESS;
815-
items[items.indexOf(item)] = item;
809+
const updatedItems = [...this.itemsRef.current];
810+
updatedItems[this.itemsRef.current.indexOf(item)] = item;
816811

817812
api.upload(uploadOptions);
818813

819-
this.updateViewAndCollection(items);
814+
this.updateViewAndCollection(updatedItems);
820815
}
821816

822817
/**
@@ -827,10 +822,9 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
827822
*/
828823
resumeFile(item: UploadItem) {
829824
const { onResume, overwrite, rootFolderId } = this.props;
830-
const { items } = this.state;
831825
const { api, file, options } = item;
832826

833-
const numItemsUploading = items.filter(item_t => item_t.status === STATUS_IN_PROGRESS).length;
827+
const numItemsUploading = this.itemsRef.current.filter(item_t => item_t.status === STATUS_IN_PROGRESS).length;
834828

835829
if (numItemsUploading >= UPLOAD_CONCURRENCY) {
836830
return;
@@ -849,12 +843,14 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
849843

850844
item.status = STATUS_IN_PROGRESS;
851845
delete item.error;
852-
items[items.indexOf(item)] = item;
846+
847+
const updatedItems = [...this.itemsRef.current];
848+
updatedItems[this.itemsRef.current.indexOf(item)] = item;
853849

854850
onResume(item);
855851
api.resume(resumeOptions);
856852

857-
this.updateViewAndCollection(items);
853+
this.updateViewAndCollection(updatedItems);
858854
}
859855

860856
/**
@@ -875,10 +871,10 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
875871
item.status = STATUS_PENDING;
876872
delete item.error;
877873

878-
const { items } = this.state;
879-
items[items.indexOf(item)] = item;
874+
const updatedItems = [...this.itemsRef.current];
875+
updatedItems[this.itemsRef.current.indexOf(item)] = item;
880876

881-
this.updateViewAndCollection(items);
877+
this.updateViewAndCollection(updatedItems);
882878
}
883879

884880
/**
@@ -903,8 +899,8 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
903899
item.boxFile = boxFile;
904900
}
905901

906-
const { items } = this.state;
907-
items[items.indexOf(item)] = item;
902+
const updatedItems = [...this.itemsRef.current];
903+
updatedItems[this.itemsRef.current.indexOf(item)] = item;
908904

909905
// Broadcast that a file has been uploaded
910906
if (useUploadsManager) {
@@ -914,7 +910,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
914910
onUpload(item.boxFile);
915911
}
916912

917-
this.updateViewAndCollection(items, () => {
913+
this.updateViewAndCollection(updatedItems, () => {
918914
const { view } = this.state;
919915
if (view === VIEW_UPLOAD_IN_PROGRESS) {
920916
this.upload();
@@ -994,10 +990,13 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
994990
};
995991

996992
if (items.length === 0) {
993+
this.itemIdsRef.current = {};
997994
state.itemIds = {};
998995
state.errorCode = '';
999996
}
1000997

998+
this.itemsRef.current = items;
999+
10011000
this.setState(state as Pick<State, keyof State>, callback);
10021001
}
10031002

@@ -1011,13 +1010,12 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
10111010
*/
10121011
handleUploadError = (item: UploadItem, error: Error) => {
10131012
const { onError, useUploadsManager } = this.props;
1014-
const { items } = this.state;
10151013
const { file } = item;
10161014

10171015
item.status = STATUS_ERROR;
10181016
item.error = error;
10191017

1020-
const newItems = [...items];
1018+
const newItems = [...this.itemsRef.current];
10211019
const index = newItems.findIndex(singleItem => singleItem === item);
10221020
if (index !== -1) {
10231021
newItems[index] = item;
@@ -1067,10 +1065,10 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
10671065
const { onProgress } = this.props;
10681066
onProgress(item);
10691067

1070-
const { items } = this.state;
1071-
items[items.indexOf(item)] = item;
1068+
const updatedItems = [...this.itemsRef.current];
1069+
updatedItems[this.itemsRef.current.indexOf(item)] = item;
10721070

1073-
this.updateViewAndCollection(items);
1071+
this.updateViewAndCollection(updatedItems);
10741072
};
10751073

10761074
/**
@@ -1119,9 +1117,7 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
11191117
* @return {void}
11201118
*/
11211119
clickAllWithStatus = (status?: UploadStatus) => {
1122-
const { items } = this.state;
1123-
1124-
items.forEach(item => {
1120+
this.itemsRef.current.forEach(item => {
11251121
if (!status || item.status === status) {
11261122
this.onClick(item);
11271123
}
@@ -1198,14 +1194,20 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
11981194
*/
11991195
resetUploadsManagerItemsWhenUploadsComplete = (): void => {
12001196
const { onCancel, useUploadsManager } = this.props;
1201-
const { isUploadsManagerExpanded, items, view } = this.state;
1197+
const { isUploadsManagerExpanded, view } = this.state;
12021198

12031199
// Do not reset items when upload manger is expanded or there're uploads in progress
1204-
if ((isUploadsManagerExpanded && useUploadsManager && !!items.length) || view === VIEW_UPLOAD_IN_PROGRESS) {
1200+
if (
1201+
(isUploadsManagerExpanded && useUploadsManager && !!this.itemsRef.current.length) ||
1202+
view === VIEW_UPLOAD_IN_PROGRESS
1203+
) {
12051204
return;
12061205
}
12071206

1208-
onCancel(items);
1207+
onCancel(this.itemsRef.current);
1208+
1209+
this.itemsRef.current = [];
1210+
this.itemIdsRef.current = {};
12091211

12101212
this.setState({
12111213
items: [],

0 commit comments

Comments
 (0)