Skip to content

Commit b2875b1

Browse files
committed
fix(form): prevent infinite rerenders when calling useFileUpload's reset in useEffect
1 parent 4746d26 commit b2875b1

2 files changed

Lines changed: 31 additions & 9 deletions

File tree

packages/form/src/file-input/__tests__/useFileUpload.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Fragment, ReactElement } from "react";
1+
import React, { Fragment, ReactElement, useEffect } from "react";
22
import filesize from "filesize";
33
import {
44
act,
@@ -436,6 +436,24 @@ describe("useFileUpload", () => {
436436
expect(() => getAllByRole("listitem")).toThrow();
437437
});
438438

439+
it("should not cause infinite rerenders if the reset function is added to a useEffect's dependency array", () => {
440+
let renders = 0;
441+
function Test(): null {
442+
const { reset } = useFileUpload();
443+
renders += 1;
444+
useEffect(() => {
445+
if (renders < 10) {
446+
reset();
447+
}
448+
}, [reset]);
449+
450+
return null;
451+
}
452+
453+
render(<Test />);
454+
expect(renders).toBe(2);
455+
});
456+
439457
it("should abort any FileReaders when the reset function is called", () => {
440458
const file = new File(["pretend-bytes"], "README.txt");
441459
const { getByLabelText, getByRole } = render(<SingleFileTest />);

packages/form/src/file-input/useFileUpload.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,9 @@ export interface FileUploadHookReturnValue<
188188
}
189189

190190
/** @internal */
191-
const DEFAULT_EXTENSIONS = [] as const;
191+
const EMPTY_LIST = [] as const;
192+
/** @internal */
193+
const EMPTY_OBJECT = {} as const;
192194

193195
/**
194196
* This hook is generally used to upload files **to the browser** in different
@@ -209,7 +211,7 @@ const DEFAULT_EXTENSIONS = [] as const;
209211
*/
210212
export function useFileUpload<E extends HTMLElement, CustomError = never>({
211213
maxFiles = -1,
212-
extensions = DEFAULT_EXTENSIONS,
214+
extensions = EMPTY_LIST,
213215
minFileSize = -1,
214216
maxFileSize = -1,
215217
totalFileSize = -1,
@@ -228,10 +230,12 @@ export function useFileUpload<E extends HTMLElement, CustomError = never>({
228230
) {
229231
switch (action.type) {
230232
case "reset":
233+
// need to reuse constants so that calling reset doesn't cause an
234+
// infinite loop in an effect
231235
return {
232-
stats: {},
233-
errors: [],
234-
readers: {},
236+
stats: EMPTY_OBJECT,
237+
errors: EMPTY_LIST,
238+
readers: EMPTY_OBJECT,
235239
};
236240
case "remove":
237241
return {
@@ -337,9 +341,9 @@ export function useFileUpload<E extends HTMLElement, CustomError = never>({
337341
}
338342
},
339343
{
340-
stats: {},
341-
errors: [],
342-
readers: {},
344+
stats: EMPTY_OBJECT,
345+
errors: EMPTY_LIST,
346+
readers: EMPTY_OBJECT,
343347
}
344348
);
345349
const { stats, errors, readers } = state;

0 commit comments

Comments
 (0)