Skip to content

Commit def5445

Browse files
committed
Fix key changing on unmount
1 parent 076cc44 commit def5445

4 files changed

Lines changed: 67 additions & 19 deletions

File tree

packages/react-dialog-async/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "react-dialog-async",
33
"description": "A promise-based way to show dialogs in React",
44
"type": "module",
5-
"version": "2.5.2",
5+
"version": "2.5.3",
66
"sideEffects": false,
77
"main": "index.js",
88
"module": "index.esm.js",

packages/react-dialog-async/src/DialogProvider/DialogProvider.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,13 @@ const DialogProvider = ({
4545
return {
4646
...state,
4747
[id]: {
48+
...state[id],
4849
open: false,
49-
dialog: state[id].dialog,
50-
data: state[id].data,
50+
resolve: undefined,
5151
},
5252
};
53-
} else {
54-
return removeKey(state, id);
5553
}
54+
return removeKey(state, id);
5655
});
5756
}, []);
5857

@@ -69,6 +68,32 @@ const DialogProvider = ({
6968
clearTimeout(unmountDelayTimeoutRefs.current[id]);
7069
}
7170

71+
function resolveFn() {
72+
setDialogState((state) => {
73+
if (!state[id]) return state;
74+
75+
if (state[id].unmountDelay) {
76+
if (unmountDelayTimeoutRefs.current[id] !== undefined) {
77+
clearTimeout(unmountDelayTimeoutRefs.current[id]);
78+
}
79+
80+
unmountDelayTimeoutRefs.current[id] = setTimeout(() => {
81+
setDialogState((state2) => removeKey(state2, id));
82+
}, state[id].unmountDelay);
83+
84+
return {
85+
...state,
86+
[id]: {
87+
...state[id],
88+
open: false,
89+
resolve: undefined,
90+
},
91+
};
92+
}
93+
return removeKey(state, id);
94+
});
95+
}
96+
7297
setDialogState((state) => {
7398
if (state[id]?.open) {
7499
resolve(undefined);
@@ -84,15 +109,15 @@ const DialogProvider = ({
84109
data,
85110
resolve: (value: any) => {
86111
resolve?.(value);
87-
hide(id);
112+
resolveFn();
88113
},
89114
unmountDelay: unmountDelay ?? defaultUnmountDelayInMs,
90115
},
91116
};
92117
});
93118
});
94119
},
95-
[hide, defaultUnmountDelayInMs],
120+
[defaultUnmountDelayInMs],
96121
);
97122

98123
/**

packages/react-dialog-async/src/DialogProvider/__snapshots__/DialogProvider.test.tsx.snap

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`calling show() mounts the dialog in the DOM 1`] = `
4-
<DocumentFragment>
5-
<div>
6-
Hello World!
7-
</div>
8-
</DocumentFragment>
9-
`;
10-
11-
exports[`calling register() followed by show() followed by hide() unmounts the dialog in the DOM 1`] = `<DocumentFragment />`;
12-
133
exports[`calling show() followed by hide() unmounts the dialog in the DOM 1`] = `<DocumentFragment />`;
144

155
exports[`calling show() mounts the dialog in the DOM 1`] = `

packages/react-dialog-async/src/useDialog.test.tsx

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ const TestWrapper = ({ children }: PropsWithChildren) => (
1616
);
1717

1818
const TestDialog = () => <div>Hello World!</div>;
19-
const TestDialogWithData = ({ data }: AsyncDialogProps<string>) => (
20-
<div>{data}</div>
19+
const TestDialogWithData = ({
20+
data,
21+
handleClose,
22+
}: AsyncDialogProps<string>) => (
23+
<div>
24+
<button data-testid={'close-btn'} onClick={() => handleClose()}></button>
25+
{data}
26+
</div>
2127
);
2228

2329
test('can be called without error', () => {
@@ -129,6 +135,33 @@ test('unmount delay does not delay the promise being resolved', async () => {
129135
expect(value).toBe(true);
130136
});
131137

138+
test('unmount delay results in the dialog remaining mounted after being closed', async () => {
139+
const message = Date.now().toString(16);
140+
const TestComponent = () => {
141+
const testDialog = useDialog(TestDialogWithData, {
142+
unmountDelayInMs: 1000,
143+
});
144+
145+
useEffect(() => {
146+
testDialog.open('Hello World!');
147+
}, []);
148+
149+
return null;
150+
};
151+
152+
render(
153+
<TestWrapper>
154+
<TestComponent />
155+
</TestWrapper>,
156+
);
157+
158+
act(() => {
159+
screen.getByTestId('close-btn').click();
160+
});
161+
162+
expect(screen.queryByText(message)).toBeDefined();
163+
});
164+
132165
test('consumer does not rerender when dialog is opened', async () => {
133166
// Track the number of renders
134167
let renderCount = 0;

0 commit comments

Comments
 (0)