diff --git a/src/Drawer.tsx b/src/Drawer.tsx index 9cff779..2d92697 100644 --- a/src/Drawer.tsx +++ b/src/Drawer.tsx @@ -41,21 +41,23 @@ const Drawer: React.FC = props => { } // ============================= Open ============================= - const [internalOpen, setInternalOpen] = React.useState(false); + const [mounted, setMounted] = React.useState(false); useLayoutEffect(() => { - setInternalOpen(open); - }, [open]); + setMounted(true); + }, []); + + const mergedOpen = mounted ? open : false; // ============================ Focus ============================= const panelRef = React.useRef(); const lastActiveRef = React.useRef(); useLayoutEffect(() => { - if (internalOpen) { + if (mergedOpen) { lastActiveRef.current = document.activeElement as HTMLElement; } - }, [internalOpen]); + }, [mergedOpen]); // ============================= Open ============================= const internalAfterOpenChange: DrawerProps['afterOpenChange'] = @@ -73,13 +75,13 @@ const Drawer: React.FC = props => { }; // ============================ Render ============================ - if (!forceRender && !animatedVisible && !internalOpen && destroyOnClose) { + if (!forceRender && !animatedVisible && !mergedOpen && destroyOnClose) { return null; } const drawerPopupProps = { ...props, - open: internalOpen, + open: mergedOpen, prefixCls, placement, autoFocus, @@ -94,10 +96,10 @@ const Drawer: React.FC = props => { return ( diff --git a/src/util.ts b/src/util.ts index 9f8eb22..b28f88c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,5 @@ import warning from 'rc-util/lib/warning'; +import canUseDom from 'rc-util/lib/Dom/canUseDom'; import type { DrawerProps } from './Drawer'; export function parseWidthHeight(value?: number | string) { @@ -18,4 +19,9 @@ export function warnCheck(props: DrawerProps) { !('wrapperClassName' in props), `'wrapperClassName' is removed. Please use 'rootClassName' instead.`, ); + + warning( + canUseDom() || !props.open, + `Drawer with 'open' in SSR is not work since no place to createPortal. Please move to 'useEffect' instead.`, + ); } diff --git a/tests/ssr.spec.tsx b/tests/ssr.spec.tsx index 4b6039d..af34004 100755 --- a/tests/ssr.spec.tsx +++ b/tests/ssr.spec.tsx @@ -43,8 +43,36 @@ describe('SSR', () => { render(, { container, hydrate: true }); - expect(errSpy).not.toHaveBeenCalled(); + expect(errSpy).toHaveBeenCalledWith( + "Warning: Drawer with 'open' in SSR is not work since no place to createPortal. Please move to 'useEffect' instead.", + ); + expect(errSpy).toBeCalledTimes(1); errSpy.mockRestore(); }); + + // Since we use `useLayoutEffect` to avoid SSR warning. + // This may affect ref call. Let's check this also. + it('should not block ref', done => { + const Demo = ({ open }: any = {}) => { + const ref = React.useRef(); + + React.useEffect(() => { + if (open) { + expect(ref.current).toBeTruthy(); + done(); + } + }, [open]); + + return ( + +
+ + ); + }; + + const { rerender } = render(); + + rerender(); + }); });