Skip to content

Commit bd34f4c

Browse files
authored
fix: not break in ssr when default open (#932)
* test: test driven * fix: Select ssr logic * chore: update default value * test: update snapshot
1 parent 60e82d7 commit bd34f4c

File tree

7 files changed

+69
-4
lines changed

7 files changed

+69
-4
lines changed

src/BaseSelect.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import classNames from 'classnames';
21
import type { AlignType } from '@rc-component/trigger/lib/interface';
2+
import classNames from 'classnames';
33
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
44
import useMergedState from 'rc-util/lib/hooks/useMergedState';
55
import isMobile from 'rc-util/lib/isMobile';
@@ -291,7 +291,7 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
291291

292292
const domProps = {
293293
...restProps,
294-
} as Omit<keyof typeof restProps, typeof DEFAULT_OMIT_PROPS[number]>;
294+
} as Omit<keyof typeof restProps, (typeof DEFAULT_OMIT_PROPS)[number]>;
295295

296296
DEFAULT_OMIT_PROPS.forEach((propName) => {
297297
delete domProps[propName];
@@ -351,12 +351,18 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
351351
);
352352

353353
// ============================== Open ==============================
354-
const [innerOpen, setInnerOpen] = useMergedState<boolean>(undefined, {
354+
// SSR not support Portal which means we need delay `open` for the first time render
355+
const [rendered, setRendered] = React.useState(false);
356+
useLayoutEffect(() => {
357+
setRendered(true);
358+
}, []);
359+
360+
const [innerOpen, setInnerOpen] = useMergedState<boolean>(false, {
355361
defaultValue: defaultOpen,
356362
value: open,
357363
});
358364

359-
let mergedOpen = innerOpen;
365+
let mergedOpen = rendered ? innerOpen : false;
360366

361367
// Not trigger `open` in `combobox` when `notFoundContent` is empty
362368
const emptyListContent = !notFoundContent && emptyOptions;

tests/__snapshots__/Combobox.test.tsx.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ exports[`Select.Combobox renders controlled correctly 1`] = `
1414
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
1515
aria-autocomplete="list"
1616
aria-controls="rc_select_TEST_OR_SSR_list"
17+
aria-expanded="false"
1718
aria-haspopup="listbox"
1819
aria-owns="rc_select_TEST_OR_SSR_list"
1920
autocomplete="off"
@@ -47,6 +48,7 @@ exports[`Select.Combobox renders correctly 1`] = `
4748
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
4849
aria-autocomplete="list"
4950
aria-controls="rc_select_TEST_OR_SSR_list"
51+
aria-expanded="false"
5052
aria-haspopup="listbox"
5153
aria-owns="rc_select_TEST_OR_SSR_list"
5254
autocomplete="off"

tests/__snapshots__/Multiple.test.tsx.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ exports[`Select.Multiple render not display maxTagPlaceholder if maxTagCount not
2222
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
2323
aria-autocomplete="list"
2424
aria-controls="rc_select_TEST_OR_SSR_list"
25+
aria-expanded="false"
2526
aria-haspopup="listbox"
2627
aria-owns="rc_select_TEST_OR_SSR_list"
2728
autocomplete="off"
@@ -142,6 +143,7 @@ exports[`Select.Multiple render truncates tags by maxTagCount and show maxTagPla
142143
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
143144
aria-autocomplete="list"
144145
aria-controls="rc_select_TEST_OR_SSR_list"
146+
aria-expanded="false"
145147
aria-haspopup="listbox"
146148
aria-owns="rc_select_TEST_OR_SSR_list"
147149
autocomplete="off"
@@ -259,6 +261,7 @@ exports[`Select.Multiple render truncates tags by maxTagCount and show maxTagPla
259261
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
260262
aria-autocomplete="list"
261263
aria-controls="rc_select_TEST_OR_SSR_list"
264+
aria-expanded="false"
262265
aria-haspopup="listbox"
263266
aria-owns="rc_select_TEST_OR_SSR_list"
264267
autocomplete="off"
@@ -360,6 +363,7 @@ exports[`Select.Multiple render truncates values by maxTagTextLength 1`] = `
360363
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
361364
aria-autocomplete="list"
362365
aria-controls="rc_select_TEST_OR_SSR_list"
366+
aria-expanded="false"
363367
aria-haspopup="listbox"
364368
aria-owns="rc_select_TEST_OR_SSR_list"
365369
autocomplete="off"

tests/__snapshots__/Select.test.tsx.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ exports[`Select.Basic no search 1`] = `
122122
aria-activedescendant="undefined_list_0"
123123
aria-autocomplete="list"
124124
aria-controls="undefined_list"
125+
aria-expanded="false"
125126
aria-haspopup="listbox"
126127
aria-owns="undefined_list"
127128
autocomplete="off"
@@ -170,6 +171,7 @@ exports[`Select.Basic render renders aria-attributes correctly 1`] = `
170171
aria-activedescendant="undefined_list_0"
171172
aria-autocomplete="list"
172173
aria-controls="undefined_list"
174+
aria-expanded="false"
173175
aria-haspopup="listbox"
174176
aria-label="some-label"
175177
aria-labelledby="test-id"
@@ -227,6 +229,7 @@ exports[`Select.Basic render renders correctly 1`] = `
227229
aria-activedescendant="undefined_list_0"
228230
aria-autocomplete="list"
229231
aria-controls="undefined_list"
232+
aria-expanded="false"
230233
aria-haspopup="listbox"
231234
aria-owns="undefined_list"
232235
autocomplete="off"
@@ -284,6 +287,7 @@ exports[`Select.Basic render renders data-attributes correctly 1`] = `
284287
aria-activedescendant="undefined_list_0"
285288
aria-autocomplete="list"
286289
aria-controls="undefined_list"
290+
aria-expanded="false"
287291
aria-haspopup="listbox"
288292
aria-owns="undefined_list"
289293
autocomplete="off"
@@ -387,6 +391,7 @@ exports[`Select.Basic render renders role prop correctly 1`] = `
387391
aria-activedescendant="undefined_list_0"
388392
aria-autocomplete="list"
389393
aria-controls="undefined_list"
394+
aria-expanded="false"
390395
aria-haspopup="listbox"
391396
aria-owns="undefined_list"
392397
autocomplete="off"

tests/__snapshots__/Tags.test.tsx.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ exports[`Select.Tags render not display maxTagPlaceholder if maxTagCount not rea
251251
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
252252
aria-autocomplete="list"
253253
aria-controls="rc_select_TEST_OR_SSR_list"
254+
aria-expanded="false"
254255
aria-haspopup="listbox"
255256
aria-owns="rc_select_TEST_OR_SSR_list"
256257
autocomplete="off"
@@ -368,6 +369,7 @@ exports[`Select.Tags render truncates tags by maxTagCount and show maxTagPlaceho
368369
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
369370
aria-autocomplete="list"
370371
aria-controls="rc_select_TEST_OR_SSR_list"
372+
aria-expanded="false"
371373
aria-haspopup="listbox"
372374
aria-owns="rc_select_TEST_OR_SSR_list"
373375
autocomplete="off"
@@ -482,6 +484,7 @@ exports[`Select.Tags render truncates tags by maxTagCount and show maxTagPlaceho
482484
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
483485
aria-autocomplete="list"
484486
aria-controls="rc_select_TEST_OR_SSR_list"
487+
aria-expanded="false"
485488
aria-haspopup="listbox"
486489
aria-owns="rc_select_TEST_OR_SSR_list"
487490
autocomplete="off"
@@ -580,6 +583,7 @@ exports[`Select.Tags render truncates values by maxTagTextLength 1`] = `
580583
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
581584
aria-autocomplete="list"
582585
aria-controls="rc_select_TEST_OR_SSR_list"
586+
aria-expanded="false"
583587
aria-haspopup="listbox"
584588
aria-owns="rc_select_TEST_OR_SSR_list"
585589
autocomplete="off"

tests/__snapshots__/ssr.test.tsx.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Select.SSR should work 1`] = `"<div class="rc-select rc-select-single rc-select-show-arrow"><div class="rc-select-selector"><span class="rc-select-selection-search"><input type="search" autoComplete="off" class="rc-select-selection-search-input" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="undefined_list" aria-autocomplete="list" aria-controls="undefined_list" aria-activedescendant="undefined_list_0" value="" readonly="" unselectable="on" style="opacity:0"/></span><span class="rc-select-selection-placeholder"></span></div><span class="rc-select-arrow" style="user-select:none;-webkit-user-select:none" unselectable="on" aria-hidden="true"><span class="rc-select-arrow-icon"></span></span></div>"`;

tests/ssr.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { render } from '@testing-library/react';
2+
import { renderToString } from 'react-dom/server';
3+
import Select from '../src';
4+
import { injectRunAllTimers } from './utils/common';
5+
6+
// Mock rc-util `canUseDom`
7+
jest.mock('rc-util/lib/Dom/canUseDom', () => {
8+
return () => global.canUseDom;
9+
});
10+
11+
jest.mock('@rc-component/trigger', () => {
12+
return jest.requireActual('@rc-component/trigger');
13+
});
14+
15+
describe('Select.SSR', () => {
16+
injectRunAllTimers(jest);
17+
18+
beforeEach(() => {
19+
global.canUseDom = true;
20+
});
21+
22+
it('should work', () => {
23+
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
24+
25+
global.canUseDom = false;
26+
27+
const Demo = () => <Select open />;
28+
const htmlStr = renderToString(<Demo />);
29+
expect(htmlStr).toMatchSnapshot();
30+
31+
// Hydrate
32+
global.canUseDom = true;
33+
const container = document.createElement('div');
34+
container.innerHTML = htmlStr;
35+
document.body.appendChild(container);
36+
render(<Demo />, { container, hydrate: true });
37+
38+
expect(errSpy).not.toHaveBeenCalled();
39+
errSpy.mockRestore();
40+
});
41+
});

0 commit comments

Comments
 (0)