Skip to content

Commit

Permalink
fix: trigger should not render portal in ssr
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Feb 14, 2023
1 parent d5ca99a commit 26b9378
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 3 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
"@testing-library/react": "^13.0.0",
"@types/classnames": "^2.2.10",
"@types/jest": "^26.0.15",
"@types/react": "^16.8.19",
"@types/react-dom": "^16.8.4",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"cross-env": "^7.0.1",
"dumi": "^2.1.0",
"eslint": "^7.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/Popup/ServerPortal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Portal will not work in SSR. We need wrap this to not to break.
*/
export default function ServerPortal(): React.ReactElement {
return null;
}
6 changes: 5 additions & 1 deletion src/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import type { CSSMotionProps } from 'rc-motion';
import CSSMotion from 'rc-motion';
import ResizeObserver from 'rc-resize-observer';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import canUseDom from 'rc-util/lib/Dom/canUseDom';
import * as React from 'react';
import type { TriggerProps } from '../';
import type { AlignType } from '../interface';
import Arrow from './Arrow';
import Mask from './Mask';
import ServerPortal from './ServerPortal';

export interface PopupProps {
prefixCls: string;
Expand Down Expand Up @@ -93,7 +95,7 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
forceRender,
getPopupContainer,
autoDestroy,
portal: Portal,
portal,

zIndex,

Expand Down Expand Up @@ -166,6 +168,8 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
miscStyle.pointerEvents = 'none';
}

const Portal = canUseDom() ? portal: ServerPortal;

return (
<Portal
open={forceRender || isNodeVisible}
Expand Down
47 changes: 47 additions & 0 deletions tests/ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { cleanup } from '@testing-library/react';
import { hydrateRoot } from 'react-dom/client';
import { renderToString } from 'react-dom/server';
import Trigger from '../src';

global.canUseDOM = false;

jest.mock('rc-util/lib/Dom/canUseDom', () => () => global.canUseDOM);

describe('Trigger.SSR', () => {
beforeEach(() => {
global.canUseDOM = false;
jest.useFakeTimers();
});

afterEach(() => {
cleanup();
jest.useRealTimers();
});

it('normal', () => {
const str = renderToString(
<Trigger popupVisible popup={<strong>trigger</strong>} arrow>
<div />
</Trigger>,
);
expect(str).toBeTruthy();
});

it('default visible should not block render', () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const node = (
<Trigger popupVisible popup={<strong>trigger</strong>} arrow>
<div />
</Trigger>
);
const str = renderToString(node);
expect(str).toBeTruthy();

console.log(str);

const div = document.createElement('div');
hydrateRoot(div, node);

expect(errSpy).not.toHaveBeenCalled();
});
});

0 comments on commit 26b9378

Please sign in to comment.