Skip to content

Commit 52830c5

Browse files
committed
Update on prop changes
1 parent 229f180 commit 52830c5

File tree

10 files changed

+111
-30
lines changed

10 files changed

+111
-30
lines changed

jest.config.pretest.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const error = global.console.error;
12
global.console = {
23
log: () => undefined, // console.log are ignored in tests
34

@@ -7,7 +8,7 @@ global.console = {
78
// Silence React "render in body" warning.
89
return;
910
}
10-
console.error(e);
11+
error(e);
1112
},
1213
warn: console.warn,
1314
info: console.info,

package-lock.json

Lines changed: 34 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"react": ">=16.3.0"
7575
},
7676
"dependencies": {
77+
"lodash.isequal": "^4.5.0",
7778
"uploader": "^3.35.0"
7879
},
7980
"devDependencies": {
@@ -84,6 +85,7 @@
8485
"@types/enzyme": "3.10.11",
8586
"@types/enzyme-adapter-react-16": "^1.0.6",
8687
"@types/jest": "27.4.1",
88+
"@types/lodash.isequal": "4.5.5",
8789
"@types/react": "16.9.56",
8890
"@types/react-dom": "16.9.9",
8991
"@typescript-eslint/eslint-plugin": "4.8.1",

src/UploadButton.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { UploaderInterface, UploadWidgetResult, UploadWidgetConfig } from "uploader";
2+
import { useAutoUpdatingOptions } from "react-uploader/hooks/UseAutoUpdatingOptions";
23

34
interface MouseEventLite {
45
preventDefault: () => void;
@@ -12,10 +13,12 @@ interface Props {
1213
}
1314

1415
export const UploadButton = ({ uploader, options, onComplete, children }: Props): JSX.Element => {
16+
const autoUpdatingOptions = useAutoUpdatingOptions(options);
17+
1518
const onClick = (e: MouseEventLite): void => {
1619
e.preventDefault();
1720

18-
uploader.open(options).then(
21+
uploader.open(autoUpdatingOptions).then(
1922
files => {
2023
if (onComplete !== undefined) {
2124
onComplete(files);

src/UploadDropzone.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { UploaderInterface, UploadWidgetResult, UploadWidgetConfig } from "uploader";
22
import React, { useLayoutEffect } from "react";
3-
import { useElementRef } from "./Utils";
3+
import { useElementRef } from "./hooks/UseElementRef";
4+
import { useAutoUpdatingOptions } from "react-uploader/hooks/UseAutoUpdatingOptions";
45

56
interface Props {
67
className?: string;
@@ -25,17 +26,16 @@ export const UploadDropzone = ({
2526
}: Props): JSX.Element => {
2627
const [element, elementRef] = useElementRef();
2728
const classNameProp = className === undefined ? {} : { className };
29+
const onUpdateParams: UploadWidgetConfig = onUpdate === undefined ? {} : { onUpdate };
30+
const autoUpdatingOptions = useAutoUpdatingOptions({ ...options, ...onUpdateParams });
2831

2932
// Prevent React warning, while keeping rendering synchronous in the browser.
3033
if (typeof window !== "undefined") {
3134
useLayoutEffect(() => {
3235
if (element !== undefined) {
33-
const onUpdateParams: UploadWidgetConfig = onUpdate === undefined ? {} : { onUpdate };
34-
3536
uploader
3637
.open({
37-
...options,
38-
...onUpdateParams,
38+
...autoUpdatingOptions,
3939
container: element,
4040
layout: "inline"
4141
})
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { UploadWidgetConfig } from "uploader";
2+
import { useObjectDep } from "react-uploader/hooks/UseObjectDep";
3+
import { useEffect, useState } from "react";
4+
import { UploadWidgetMethods } from "uploader/dist/config/UploadWidgetMethods";
5+
6+
export function useAutoUpdatingOptions(optionsMaybe: UploadWidgetConfig | undefined): UploadWidgetConfig {
7+
const [methods, setMethods] = useState<UploadWidgetMethods | undefined>(undefined);
8+
const optionsDep = useObjectDep(optionsMaybe ?? {});
9+
10+
useEffect(() => {
11+
if (methods !== undefined) {
12+
methods.updateConfig(optionsMaybe ?? {});
13+
}
14+
}, [optionsDep, methods]);
15+
16+
return {
17+
...optionsMaybe,
18+
onInit: m => {
19+
if (optionsMaybe?.onInit !== undefined) {
20+
optionsMaybe.onInit(m);
21+
}
22+
setMethods(m);
23+
}
24+
};
25+
}
File renamed without changes.

src/hooks/UseObjectDep.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { useRef } from "react";
2+
import isEqual from "lodash.isequal";
3+
4+
export function useObjectDep<T>(value: T): T {
5+
const ref = useRef<T>();
6+
7+
if (!isEqual(value, ref.current)) {
8+
ref.current = value;
9+
}
10+
11+
return ref.current ?? value;
12+
}

tests/UploadButton.test.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,40 @@ import React from "react";
33
import { Uploader } from "uploader";
44
import { configure, mount } from "enzyme";
55
import Adapter from "enzyme-adapter-react-16";
6+
import { act } from "react-dom/test-utils";
67

78
(global as any).ResizeObserver = require("resize-observer-polyfill");
89
const uploader = Uploader({ apiKey: "free" });
910
configure({ adapter: new Adapter() });
1011

1112
describe("UploadButton Component", () => {
1213
test("Renders the given child", () => {
13-
const html = mount(
14-
<UploadButton uploader={uploader}>{({ onClick }) => <button onClick={onClick}>Click Me</button>}</UploadButton>
15-
);
16-
expect(html.text()).toEqual("Click Me");
14+
act(() => {
15+
const html = mount(
16+
<UploadButton uploader={uploader}>{({ onClick }) => <button onClick={onClick}>Click Me</button>}</UploadButton>
17+
);
18+
expect(html.text()).toEqual("Click Me");
19+
});
1720
});
1821

1922
test("Displays the Uploader modal when clicked", async () => {
20-
const html = mount(
21-
<div>
22-
<UploadButton uploader={uploader} options={{ container: "#container" }}>
23-
{({ onClick }) => <button onClick={onClick}>Click Me</button>}
24-
</UploadButton>
25-
<div id="container" />
26-
</div>,
27-
{ attachTo: document.body }
28-
);
23+
await act(async () => {
24+
const html = mount(
25+
<div>
26+
<UploadButton uploader={uploader} options={{ container: "#container" }}>
27+
{({ onClick }) => <button onClick={onClick}>Click Me</button>}
28+
</UploadButton>
29+
<div id="container" />
30+
</div>,
31+
{ attachTo: document.body }
32+
);
2933

30-
html.find("button").simulate("click");
34+
html.find("button").simulate("click");
3135

32-
await tick();
36+
await tick();
3337

34-
expect(html.html()).toContain("Upload a File");
38+
expect(html.html()).toContain("Upload a File");
39+
});
3540
});
3641
});
3742

tests/UploadDropzone.test.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ import { Uploader } from "uploader";
33
import { configure, mount } from "enzyme";
44
import Adapter from "enzyme-adapter-react-16";
55
import { UploadDropzone } from "react-uploader/UploadDropzone";
6+
import { act } from "react-dom/test-utils";
67

78
(global as any).ResizeObserver = require("resize-observer-polyfill");
89
const uploader = Uploader({ apiKey: "free" });
910
configure({ adapter: new Adapter() });
1011

1112
describe("UploadDropzone Component", () => {
1213
test("Renders the Uploader component inline", async () => {
13-
const html = mount(<UploadDropzone uploader={uploader} />, { attachTo: document.body });
14-
await tick();
15-
expect(html.html()).toContain("Upload a File");
14+
await act(async () => {
15+
const html = mount(<UploadDropzone uploader={uploader} />, { attachTo: document.body });
16+
await tick();
17+
expect(html.html()).toContain("Upload a File");
18+
});
1619
});
1720
});
1821

0 commit comments

Comments
 (0)