Skip to content

Commit fc5dfe7

Browse files
authored
fix: Chrome render perf issue (#1045)
* fix: chrome render bug * chore: cut 50
1 parent 51792a5 commit fc5dfe7

File tree

4 files changed

+94
-30
lines changed

4 files changed

+94
-30
lines changed

src/BaseSelect/Polite.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import type { DisplayValueType } from '.';
3+
4+
export interface PoliteProps {
5+
visible: boolean;
6+
values: DisplayValueType[];
7+
}
8+
9+
export default function Polite(props: PoliteProps) {
10+
const { visible, values } = props;
11+
12+
if (!visible) {
13+
return null;
14+
}
15+
16+
// Only cut part of values since it's a screen reader
17+
const MAX_COUNT = 50;
18+
19+
return (
20+
<span
21+
aria-live="polite"
22+
style={{ width: 0, height: 0, position: 'absolute', overflow: 'hidden', opacity: 0 }}
23+
>
24+
{/* Merge into one string to make screen reader work as expect */}
25+
{`${values
26+
.slice(0, MAX_COUNT)
27+
.map(({ label, value }) => (['number', 'string'].includes(typeof label) ? label : value))
28+
.join(', ')}`}
29+
{values.length > MAX_COUNT ? ', ...' : null}
30+
</span>
31+
);
32+
}

src/BaseSelect.tsx renamed to src/BaseSelect/index.tsx

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import KeyCode from 'rc-util/lib/KeyCode';
77
import { useComposeRef } from 'rc-util/lib/ref';
88
import type { ScrollConfig, ScrollTo } from 'rc-virtual-list/lib/List';
99
import * as React from 'react';
10-
import { useAllowClear } from './hooks/useAllowClear';
11-
import { BaseSelectContext } from './hooks/useBaseProps';
12-
import type { BaseSelectContextProps } from './hooks/useBaseProps';
13-
import useDelayReset from './hooks/useDelayReset';
14-
import useLock from './hooks/useLock';
15-
import useSelectTriggerControl from './hooks/useSelectTriggerControl';
10+
import { useAllowClear } from '../hooks/useAllowClear';
11+
import { BaseSelectContext } from '../hooks/useBaseProps';
12+
import type { BaseSelectContextProps } from '../hooks/useBaseProps';
13+
import useDelayReset from '../hooks/useDelayReset';
14+
import useLock from '../hooks/useLock';
15+
import useSelectTriggerControl from '../hooks/useSelectTriggerControl';
1616
import type {
1717
DisplayInfoType,
1818
DisplayValueType,
@@ -21,15 +21,16 @@ import type {
2121
RawValueType,
2222
RenderDOMFunc,
2323
RenderNode,
24-
} from './interface';
25-
import type { RefSelectorProps } from './Selector';
26-
import Selector from './Selector';
27-
import type { RefTriggerProps } from './SelectTrigger';
28-
import SelectTrigger from './SelectTrigger';
29-
import TransBtn from './TransBtn';
30-
import { getSeparatedContent, isValidCount } from './utils/valueUtil';
31-
import SelectContext from './SelectContext';
32-
import type { SelectContextProps } from './SelectContext';
24+
} from '../interface';
25+
import type { RefSelectorProps } from '../Selector';
26+
import Selector from '../Selector';
27+
import type { RefTriggerProps } from '../SelectTrigger';
28+
import SelectTrigger from '../SelectTrigger';
29+
import TransBtn from '../TransBtn';
30+
import { getSeparatedContent, isValidCount } from '../utils/valueUtil';
31+
import SelectContext from '../SelectContext';
32+
import type { SelectContextProps } from '../SelectContext';
33+
import Polite from './Polite';
3334

3435
export type {
3536
DisplayInfoType,
@@ -816,19 +817,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
816817
onFocus={onContainerFocus}
817818
onBlur={onContainerBlur}
818819
>
819-
{mockFocused && !mergedOpen && (
820-
<span
821-
aria-live="polite"
822-
style={{ width: 0, height: 0, position: 'absolute', overflow: 'hidden', opacity: 0 }}
823-
>
824-
{/* Merge into one string to make screen reader work as expect */}
825-
{`${displayValues
826-
.map(({ label, value }) =>
827-
['number', 'string'].includes(typeof label) ? label : value,
828-
)
829-
.join(', ')}`}
830-
</span>
831-
)}
820+
<Polite visible={mockFocused && !mergedOpen} values={displayValues} />
832821
{selectorNode}
833822
{arrowNode}
834823
{mergedAllowClear && clearNode}

tests/BaseSelect.test.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,43 @@ describe('BaseSelect', () => {
6262
jest.useRealTimers();
6363
});
6464

65+
// https://github.com/ant-design/ant-design/issues/48833
66+
it('a11y not block of Chrome render', () => {
67+
jest.useFakeTimers();
68+
69+
const { container } = render(
70+
<BaseSelect
71+
displayValues={Array.from({ length: 100 }).map((_, index) => ({
72+
key: index,
73+
value: index,
74+
label: index,
75+
}))}
76+
id="test"
77+
prefixCls="rc-select"
78+
onDisplayValuesChange={() => {}}
79+
searchValue=""
80+
onSearch={() => {}}
81+
OptionList={OptionList}
82+
emptyOptions
83+
/>,
84+
);
85+
86+
fireEvent.focus(container.querySelector('div.rc-select'));
87+
act(() => {
88+
jest.runAllTimers();
89+
});
90+
91+
// We cut 50 count as hard code, its safe to adjust if refactor
92+
const contentTxt = container.querySelector('span[aria-live=polite]')?.textContent;
93+
expect(contentTxt).toBe(
94+
`${Array.from({ length: 50 })
95+
.map((_, index) => index)
96+
.join(', ')}, ...`,
97+
);
98+
99+
jest.useRealTimers();
100+
});
101+
65102
it('customize builtinPlacements should override default one', () => {
66103
const { container } = render(
67104
<BaseSelect

tests/Select.test.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import type { LabelInValueType } from '@/Select';
2-
import { createEvent, fireEvent, render, render as testingRender } from '@testing-library/react';
2+
import {
3+
createEvent,
4+
fireEvent,
5+
render,
6+
render as testingRender,
7+
act,
8+
} from '@testing-library/react';
39
import KeyCode from 'rc-util/lib/KeyCode';
410
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
511
import { resetWarned } from 'rc-util/lib/warning';
612
import type { ScrollConfig } from 'rc-virtual-list/lib/List';
7-
import React, { act } from 'react';
13+
import React from 'react';
814
import type { SelectProps } from '../src';
915
import Select, { OptGroup, Option, useBaseProps } from '../src';
1016
import type { BaseSelectRef } from '../src/BaseSelect';

0 commit comments

Comments
 (0)