Skip to content

Commit c85545d

Browse files
TkDodoandrewshie-sentry
authored andcommitted
ref: remove domId (#87839)
since React18, we can use the built-in hook `useId` to provide a stable id that can be used in the dom. I couldn't remove the function because two occurrences in class components remain, but I've marked it as deprecated
1 parent 1f575be commit c85545d

File tree

18 files changed

+80
-72
lines changed

18 files changed

+80
-72
lines changed

static/app/components/activity/note/input.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useCallback, useMemo, useState} from 'react';
1+
import {useCallback, useId, useState} from 'react';
22
import type {MentionsInputProps} from 'react-mentions';
33
import {Mention, MentionsInput} from 'react-mentions';
44
import type {Theme} from '@emotion/react';
@@ -12,7 +12,6 @@ import {t} from 'sentry/locale';
1212
import {space} from 'sentry/styles/space';
1313
import textStyles from 'sentry/styles/text';
1414
import type {NoteType} from 'sentry/types/alerts';
15-
import domId from 'sentry/utils/domId';
1615
import marked from 'sentry/utils/marked';
1716
import {useMembers} from 'sentry/utils/useMembers';
1817
import {useTeams} from 'sentry/utils/useTeams';
@@ -149,7 +148,7 @@ function NoteInput({
149148
[canSubmit, submitForm]
150149
);
151150

152-
const errorId = useMemo(() => domId('note-error-'), []);
151+
const errorId = useId();
153152
const errorMessage =
154153
(errorJSON &&
155154
(typeof errorJSON.detail === 'string'

static/app/components/compactSelect/gridList/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import {Fragment, useCallback, useContext, useMemo, useRef} from 'react';
1+
import {Fragment, useCallback, useContext, useId, useMemo, useRef} from 'react';
22
import type {AriaGridListOptions} from '@react-aria/gridlist';
33
import {useGridList} from '@react-aria/gridlist';
44
import {mergeProps} from '@react-aria/utils';
55
import type {ListState} from '@react-stately/list';
66
import type {CollectionChildren} from '@react-types/shared';
77

88
import {t} from 'sentry/locale';
9-
import domId from 'sentry/utils/domId';
109
import type {FormSize} from 'sentry/utils/theme';
1110

1211
import {SelectContext} from '../control';
@@ -76,7 +75,7 @@ function GridList({
7675
...props
7776
}: GridListProps) {
7877
const ref = useRef<HTMLUListElement>(null);
79-
const labelId = domId('grid-label-');
78+
const labelId = useId();
8079
const {gridProps} = useGridList(
8180
{...props, 'aria-labelledby': label ? labelId : props['aria-labelledby']},
8281
listState,

static/app/components/compactSelect/gridList/section.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import {Fragment, useContext, useMemo} from 'react';
1+
import {Fragment, useContext, useId, useMemo} from 'react';
22
import {useSeparator} from '@react-aria/separator';
33
import type {ListState} from '@react-stately/list';
44
import type {Node} from '@react-types/shared';
55

6-
import domId from 'sentry/utils/domId';
76
import type {FormSize} from 'sentry/utils/theme';
87

98
import {SelectFilterContext} from '../list';
@@ -31,7 +30,7 @@ interface GridListSectionProps {
3130
* inside). https://react-spectrum.adobe.com/react-aria/useGridList.html
3231
*/
3332
export function GridListSection({node, listState, onToggle, size}: GridListSectionProps) {
34-
const titleId = domId('grid-section-title-');
33+
const titleId = useId();
3534
const {separatorProps} = useSeparator({elementType: 'li'});
3635

3736
const showToggleAllButton =

static/app/components/compactSelect/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import {useMemo} from 'react';
1+
import {useId, useMemo} from 'react';
22
import {Item, Section} from '@react-stately/collections';
33

44
import {t} from 'sentry/locale';
5-
import domId from 'sentry/utils/domId';
65

76
import type {ControlProps} from './control';
87
import {Control} from './control';
@@ -80,7 +79,7 @@ function CompactSelect<Value extends SelectKey>({
8079
triggerProps,
8180
...controlProps
8281
}: SelectProps<Value>) {
83-
const triggerId = useMemo(() => domId('select-trigger-'), []);
82+
const triggerId = useId();
8483

8584
// Combine list props into an object with two clearly separated types, one where
8685
// `multiple` is true and the other where it's not. Necessary to avoid TS errors.

static/app/components/compactSelect/list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Fragment,
44
useCallback,
55
useContext,
6+
useId,
67
useLayoutEffect,
78
useMemo,
89
} from 'react';
@@ -13,7 +14,6 @@ import type {ListProps} from '@react-stately/list';
1314
import {useListState} from '@react-stately/list';
1415

1516
import {defined} from 'sentry/utils';
16-
import domId from 'sentry/utils/domId';
1717
import type {FormSize} from 'sentry/utils/theme';
1818

1919
import {SelectContext} from './control';
@@ -337,7 +337,7 @@ function List<Value extends SelectKey>({
337337
]
338338
);
339339

340-
const listId = useMemo(() => domId('select-list-'), []);
340+
const listId = useId();
341341

342342
const sections = useMemo(
343343
() =>

static/app/components/compactSelect/utils.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,19 +271,19 @@ export function HiddenSectionToggle({
271271
// Highlight this toggle's visible counterpart (rendered inside the list box) on focus
272272
const {focusProps} = useFocus({
273273
onFocus: () => {
274-
const visibleCounterpart = document.querySelector(
275-
`#${listId} button[aria-hidden][data-key="${item.key}"]`
276-
);
274+
const visibleCounterpart = document
275+
.getElementById(listId)
276+
?.querySelector(`button[aria-hidden][data-key="${item.key}"]`);
277277

278278
if (!visibleCounterpart) {
279279
return;
280280
}
281281
visibleCounterpart.classList.add('focus-visible');
282282
},
283283
onBlur: () => {
284-
const visibleCounterpart = document.querySelector(
285-
`#${listId} button[aria-hidden][data-key="${item.key}"]`
286-
);
284+
const visibleCounterpart = document
285+
.getElementById(listId)
286+
?.querySelector(`button[aria-hidden][data-key="${item.key}"]`);
287287

288288
if (!visibleCounterpart) {
289289
return;

static/app/components/core/menuListItem/index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {forwardRef as reactForwardRef, memo, useMemo, useRef, useState} from 'react';
1+
import {forwardRef as reactForwardRef, memo, useId, useRef, useState} from 'react';
22
import {createPortal} from 'react-dom';
33
import {usePopper} from 'react-popper';
44
import isPropValid from '@emotion/is-prop-valid';
@@ -19,7 +19,6 @@ import {Overlay, PositionWrapper} from 'sentry/components/overlay';
1919
import type {TooltipProps} from 'sentry/components/tooltip';
2020
import {Tooltip} from 'sentry/components/tooltip';
2121
import {space} from 'sentry/styles/space';
22-
import domId from 'sentry/utils/domId';
2322
import mergeRefs from 'sentry/utils/mergeRefs';
2423
import type {FormSize} from 'sentry/utils/theme';
2524
import {withChonk} from 'sentry/utils/theme/withChonk';
@@ -121,8 +120,8 @@ function BaseMenuListItem({
121120
...props
122121
}: Props) {
123122
const itemRef = useRef<HTMLLIElement>(null);
124-
const labelId = useMemo(() => domId('menuitem-label-'), []);
125-
const detailId = useMemo(() => domId('menuitem-details-'), []);
123+
const labelId = useId();
124+
const detailId = useId();
126125

127126
return (
128127
<MenuItemWrap

static/app/components/hovercard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function Hovercard({
116116
tipColor = 'backgroundElevated',
117117
...hoverOverlayProps
118118
}: HovercardProps): React.ReactElement {
119-
const {wrapTrigger, isOpen, ...hoverOverlayState} = useHoverOverlay('hovercard', {
119+
const {wrapTrigger, isOpen, ...hoverOverlayState} = useHoverOverlay({
120120
offset,
121121
displayTimeout,
122122
isHoverable: true,

static/app/components/overlayArrow.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import {forwardRef, useMemo} from 'react';
1+
import {forwardRef, useId} from 'react';
22
import type {PopperProps} from 'react-popper';
33
import styled from '@emotion/styled';
44

5-
import domId from 'sentry/utils/domId';
65
import type {ColorOrAlias} from 'sentry/utils/theme';
76

87
interface OverlayArrowProps extends React.ComponentPropsWithRef<'div'> {
@@ -42,8 +41,8 @@ function BaseOverlayArrow(
4241
`C ${w * 0.55} ${s / 2} ${w * 0.75} ${h - s / 2} ${w} ${h - s / 2}`,
4342
].join('');
4443

45-
const strokeMaskId = useMemo(() => domId('stroke-mask'), []);
46-
const fillMaskId = useMemo(() => domId('fill-mask'), []);
44+
const strokeMaskId = useId();
45+
const fillMaskId = useId();
4746

4847
return (
4948
<Wrap ref={ref} placement={placement} size={size} {...props}>

static/app/components/timeRangeSelector/dateRange.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
isValidTime,
2020
setDateToTime,
2121
} from 'sentry/utils/dates';
22-
import domId from 'sentry/utils/domId';
22+
import {domId} from 'sentry/utils/domId';
2323
import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes';
2424
// eslint-disable-next-line no-restricted-imports
2525
import withSentryRouter from 'sentry/utils/withSentryRouter';

static/app/components/tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function Tooltip({
6060
arrowProps,
6161
reset,
6262
update,
63-
} = useHoverOverlay('tooltip', hoverOverlayProps);
63+
} = useHoverOverlay(hoverOverlayProps);
6464

6565
const {forceVisible} = hoverOverlayProps;
6666

static/app/utils/domId.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
function domId(prefix: string): string {
1+
/**
2+
* @deprecated
3+
* prefer `useId` from `React` instead
4+
*/
5+
export function domId(prefix: string): string {
26
return prefix + Math.random().toString(36).substring(2, 12);
37
}
4-
5-
export default domId;

static/app/utils/replays/replayReader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import memoize from 'lodash/memoize';
33
import {type Duration, duration} from 'moment-timezone';
44

55
import {defined} from 'sentry/utils';
6-
import domId from 'sentry/utils/domId';
6+
import {domId} from 'sentry/utils/domId';
77
import localStorageWrapper from 'sentry/utils/localStorage';
88
import clamp from 'sentry/utils/number/clamp';
99
import extractDomNodes from 'sentry/utils/replays/extractDomNodes';

static/app/utils/useHoverOverlay.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
33
import {useHoverOverlay} from 'sentry/utils/useHoverOverlay';
44

55
function Component(props: Partial<React.HTMLAttributes<HTMLInputElement>>) {
6-
const {wrapTrigger} = useHoverOverlay('test', {skipWrapper: true});
6+
const {wrapTrigger} = useHoverOverlay({skipWrapper: true});
77

88
return wrapTrigger(<input {...props} />);
99
}

static/app/utils/useHoverOverlay.tsx

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
isValidElement,
44
useCallback,
55
useEffect,
6+
useId,
67
useMemo,
78
useRef,
89
useState,
@@ -12,7 +13,6 @@ import {usePopper} from 'react-popper';
1213
import {useTheme} from '@emotion/react';
1314
import {mergeProps} from '@react-aria/utils';
1415

15-
import domId from 'sentry/utils/domId';
1616
import type {ColorOrAlias} from 'sentry/utils/theme';
1717

1818
function makeDefaultPopperModifiers(arrowElement: HTMLElement | null, offset: number) {
@@ -163,28 +163,25 @@ function maybeClearRefTimeout(ref: React.MutableRefObject<number | undefined>) {
163163
/**
164164
* A hook used to trigger a positioned overlay on hover.
165165
*/
166-
function useHoverOverlay(
167-
overlayType: string,
168-
{
169-
className,
170-
style,
171-
delay,
172-
displayTimeout,
173-
isHoverable,
174-
showUnderline,
175-
underlineColor,
176-
showOnlyOnOverflow,
177-
skipWrapper,
178-
forceVisible,
179-
offset = 8,
180-
position = 'top',
181-
containerDisplayMode = 'inline-block',
182-
onHover,
183-
onBlur,
184-
}: UseHoverOverlayProps
185-
) {
166+
function useHoverOverlay({
167+
className,
168+
style,
169+
delay,
170+
displayTimeout,
171+
isHoverable,
172+
showUnderline,
173+
underlineColor,
174+
showOnlyOnOverflow,
175+
skipWrapper,
176+
forceVisible,
177+
offset = 8,
178+
position = 'top',
179+
containerDisplayMode = 'inline-block',
180+
onHover,
181+
onBlur,
182+
}: UseHoverOverlayProps) {
186183
const theme = useTheme();
187-
const describeById = useMemo(() => domId(`${overlayType}-`), [overlayType]);
184+
const describeById = useId();
188185

189186
const [isVisible, setIsVisible] = useState(forceVisible ?? false);
190187
const isOpen = forceVisible ?? isVisible;

static/app/views/issueDetails/streamline/sidebar/note.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useCallback, useMemo, useState} from 'react';
1+
import {useCallback, useId, useState} from 'react';
22
import type {MentionsInputProps} from 'react-mentions';
33
import {Mention, MentionsInput} from 'react-mentions';
44
import type {Theme} from '@emotion/react';
@@ -16,7 +16,6 @@ import {ButtonBar} from 'sentry/components/core/button/buttonBar';
1616
import {t} from 'sentry/locale';
1717
import {space} from 'sentry/styles/space';
1818
import type {NoteType} from 'sentry/types/alerts';
19-
import domId from 'sentry/utils/domId';
2019
import {useMembers} from 'sentry/utils/useMembers';
2120
import {useTeams} from 'sentry/utils/useTeams';
2221

@@ -136,7 +135,7 @@ function StreamlinedNoteInput({
136135
[canSubmit, handleSubmit]
137136
);
138137

139-
const errorId = useMemo(() => domId('note-error-'), []);
138+
const errorId = useId();
140139
const errorMessage =
141140
(errorJSON &&
142141
(typeof errorJSON.detail === 'string'

static/app/views/replays/detail/memoryPanel/memoryChart.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
import type {Dispatch, SetStateAction} from 'react';
2-
import {forwardRef, memo, useCallback, useEffect, useMemo, useRef} from 'react';
1+
import {
2+
type Dispatch,
3+
forwardRef,
4+
memo,
5+
type SetStateAction,
6+
useCallback,
7+
useEffect,
8+
useId,
9+
useMemo,
10+
useRef,
11+
} from 'react';
312
import {useTheme} from '@emotion/react';
413

514
import type {AreaChartProps, AreaChartSeries} from 'sentry/components/charts/areaChart';
@@ -15,7 +24,6 @@ import type {ReactEchartsRef} from 'sentry/types/echarts';
1524
import toArray from 'sentry/utils/array/toArray';
1625
import {formatBytesBase2} from 'sentry/utils/bytes/formatBytesBase2';
1726
import {getFormattedDate} from 'sentry/utils/dates';
18-
import domId from 'sentry/utils/domId';
1927
import formatDuration from 'sentry/utils/duration/formatDuration';
2028
import type {MemoryFrame} from 'sentry/utils/replays/types';
2129

@@ -128,7 +136,7 @@ const MemoryChartSeries = memo(
128136
forwardRef<ReactEchartsRef, MemoryChartSeriesProps>(
129137
({durationMs, memoryFrames, startTimestampMs}, ref) => {
130138
const theme = useTheme();
131-
const idRef = useRef(domId('replay-memory-chart-'));
139+
const chartId = useId();
132140
const chartOptions: Omit<AreaChartProps, 'series'> = useMemo(
133141
() => ({
134142
autoHeightResize: true,
@@ -142,7 +150,7 @@ const MemoryChartSeries = memo(
142150
appendToBody: true,
143151
trigger: 'axis',
144152
renderMode: 'html',
145-
chartId: idRef.current,
153+
chartId,
146154
formatter: values => {
147155
const firstValue = Array.isArray(values) ? values[0] : values;
148156
const seriesTooltips = toArray(values).map(
@@ -197,7 +205,7 @@ const MemoryChartSeries = memo(
197205
},
198206
}),
199207
}),
200-
[startTimestampMs, theme]
208+
[startTimestampMs, theme, chartId]
201209
);
202210

203211
const staticSeries = useMemo<AreaChartSeries[]>(
@@ -264,7 +272,7 @@ const MemoryChartSeries = memo(
264272
);
265273

266274
return (
267-
<div id={idRef.current}>
275+
<div id={chartId}>
268276
<AreaChart ref={ref} {...chartOptions} series={series} />
269277
</div>
270278
);

0 commit comments

Comments
 (0)