Skip to content

Commit 4700884

Browse files
authored
fix: client render should keep sync (#412)
1 parent adbc9a1 commit 4700884

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

src/Drawer.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,23 @@ const Drawer: React.FC<DrawerProps> = props => {
4141
}
4242

4343
// ============================= Open =============================
44-
const [internalOpen, setInternalOpen] = React.useState(false);
44+
const [mounted, setMounted] = React.useState(false);
4545

4646
useLayoutEffect(() => {
47-
setInternalOpen(open);
48-
}, [open]);
47+
setMounted(true);
48+
}, []);
49+
50+
const mergedOpen = mounted ? open : false;
4951

5052
// ============================ Focus =============================
5153
const panelRef = React.useRef<HTMLDivElement>();
5254

5355
const lastActiveRef = React.useRef<HTMLElement>();
5456
useLayoutEffect(() => {
55-
if (internalOpen) {
57+
if (mergedOpen) {
5658
lastActiveRef.current = document.activeElement as HTMLElement;
5759
}
58-
}, [internalOpen]);
60+
}, [mergedOpen]);
5961

6062
// ============================= Open =============================
6163
const internalAfterOpenChange: DrawerProps['afterOpenChange'] =
@@ -73,13 +75,13 @@ const Drawer: React.FC<DrawerProps> = props => {
7375
};
7476

7577
// ============================ Render ============================
76-
if (!forceRender && !animatedVisible && !internalOpen && destroyOnClose) {
78+
if (!forceRender && !animatedVisible && !mergedOpen && destroyOnClose) {
7779
return null;
7880
}
7981

8082
const drawerPopupProps = {
8183
...props,
82-
open: internalOpen,
84+
open: mergedOpen,
8385
prefixCls,
8486
placement,
8587
autoFocus,
@@ -94,10 +96,10 @@ const Drawer: React.FC<DrawerProps> = props => {
9496

9597
return (
9698
<Portal
97-
open={internalOpen || forceRender || animatedVisible}
99+
open={mergedOpen || forceRender || animatedVisible}
98100
autoDestroy={false}
99101
getContainer={getContainer}
100-
autoLock={mask && (internalOpen || animatedVisible)}
102+
autoLock={mask && (mergedOpen || animatedVisible)}
101103
>
102104
<DrawerPopup {...drawerPopupProps} />
103105
</Portal>

src/util.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import warning from 'rc-util/lib/warning';
2+
import canUseDom from 'rc-util/lib/Dom/canUseDom';
23
import type { DrawerProps } from './Drawer';
34

45
export function parseWidthHeight(value?: number | string) {
@@ -18,4 +19,9 @@ export function warnCheck(props: DrawerProps) {
1819
!('wrapperClassName' in props),
1920
`'wrapperClassName' is removed. Please use 'rootClassName' instead.`,
2021
);
22+
23+
warning(
24+
canUseDom() || !props.open,
25+
`Drawer with 'open' in SSR is not work since no place to createPortal. Please move to 'useEffect' instead.`,
26+
);
2127
}

tests/ssr.spec.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,36 @@ describe('SSR', () => {
4343

4444
render(<Demo />, { container, hydrate: true });
4545

46-
expect(errSpy).not.toHaveBeenCalled();
46+
expect(errSpy).toHaveBeenCalledWith(
47+
"Warning: Drawer with 'open' in SSR is not work since no place to createPortal. Please move to 'useEffect' instead.",
48+
);
49+
expect(errSpy).toBeCalledTimes(1);
4750

4851
errSpy.mockRestore();
4952
});
53+
54+
// Since we use `useLayoutEffect` to avoid SSR warning.
55+
// This may affect ref call. Let's check this also.
56+
it('should not block ref', done => {
57+
const Demo = ({ open }: any = {}) => {
58+
const ref = React.useRef<HTMLDivElement>();
59+
60+
React.useEffect(() => {
61+
if (open) {
62+
expect(ref.current).toBeTruthy();
63+
done();
64+
}
65+
}, [open]);
66+
67+
return (
68+
<Drawer open={open}>
69+
<div ref={ref} className="bamboo" />
70+
</Drawer>
71+
);
72+
};
73+
74+
const { rerender } = render(<Demo />);
75+
76+
rerender(<Demo open />);
77+
});
5078
});

0 commit comments

Comments
 (0)