Skip to content

Commit 0baa5a7

Browse files
authored
Use isomorphic layout effect everywhere (#3722)
* use isomorphic layout effect instead of layout effect * changeset * fix namespace
1 parent 500e529 commit 0baa5a7

File tree

9 files changed

+30
-20
lines changed

9 files changed

+30
-20
lines changed

.changeset/two-seals-prove.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@primer/react': patch
3+
---
4+
5+
use isomorphic layout effects only
6+
7+
<!-- Changed components: InlineAutocomplete, MarkdownEditor -->

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ module.exports = {
143143
importNames: ['useSSRSafeId'],
144144
message: 'Please use the `useId` hook from `src/hooks/useId.ts` instead',
145145
},
146+
{
147+
name: 'react',
148+
importNames: ['useLayoutEffect'],
149+
message:
150+
'Please use the `useIsomorphicLayoutEffect` hook from `src/hooks/useIsomorphicLayoutEffect.ts` instead',
151+
},
146152
],
147153
patterns: [
148154
{

src/drafts/InlineAutocomplete/InlineAutocomplete.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import React, {useLayoutEffect, useState} from 'react'
1+
import React, {useState} from 'react'
22
import {fireEvent, render, within} from '@testing-library/react'
33
import userEvent from '@testing-library/user-event'
44
import InlineAutocomplete, {ShowSuggestionsEvent, Suggestions, Trigger} from '.'
55
import FormControl from '../../FormControl'
66
import {ActionList} from '../../ActionList'
77
import Textarea from '../../Textarea'
88
import ThemeProvider from '../../ThemeProvider'
9+
import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect'
910

1011
const label = 'Inline Autocomplete'
1112

@@ -82,7 +83,7 @@ const UncontrolledInlineAutocomplete = ({
8283
}
8384
}
8485

85-
useLayoutEffect(() => {
86+
useIsomorphicLayoutEffect(() => {
8687
// combobox-nav attempts to filter out 'hidden' options by checking if the option has an
8788
// offsetHeight or width > 0. In JSDom, all elements have offsetHeight = offsetWidth = 0,
8889
// so we need to override at least one to make the class recognize that any options exist.

src/drafts/MarkdownEditor/MarkdownEditor.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
1-
import React, {
2-
forwardRef,
3-
useCallback,
4-
useEffect,
5-
useImperativeHandle,
6-
useLayoutEffect,
7-
useMemo,
8-
useRef,
9-
useState,
10-
} from 'react'
1+
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'
112
import Box from '../../Box'
123
import VisuallyHidden from '../../_VisuallyHidden'
134
import {useId} from '../../hooks/useId'
@@ -36,6 +27,7 @@ import {Emoji} from './suggestions/_useEmojiSuggestions'
3627
import {Mentionable} from './suggestions/_useMentionSuggestions'
3728
import {Reference} from './suggestions/_useReferenceSuggestions'
3829
import {isModifierKey} from './utils'
30+
import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect'
3931

4032
export type MarkdownEditorProps = SxProp & {
4133
/** Current value of the editor as a multiline markdown string. */
@@ -268,7 +260,7 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
268260
useResizeObserver(onResize, containerRef)
269261

270262
// workaround for Safari bug where layout is otherwise not recalculated
271-
useLayoutEffect(() => {
263+
useIsomorphicLayoutEffect(() => {
272264
const container = containerRef.current
273265
if (!container) return
274266

src/drafts/hooks/useCombobox.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Combobox from '@github/combobox-nav'
2-
import {useCallback, useEffect, useLayoutEffect, useRef, useState} from 'react'
2+
import {useCallback, useEffect, useRef, useState} from 'react'
33
import {useId} from '../../hooks/useId'
4+
import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect'
45

56
export type ComboboxCommitEvent<T> = {
67
/** The underlying `combobox-commit` event. */
@@ -138,7 +139,7 @@ export const useCombobox = <T>({
138139
[onCommit, list],
139140
)
140141

141-
useLayoutEffect(() => {
142+
useIsomorphicLayoutEffect(() => {
142143
const optionElements = getOptionElements()
143144
// Ensure each option has a unique ID (required by the Combobox class), but respect user provided IDs
144145
for (const [i, option] of optionElements.entries()) {

src/drafts/hooks/useDynamicTextareaHeight.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import {RefObject, useCallback, useEffect, useLayoutEffect, useState} from 'react'
1+
import {RefObject, useCallback, useEffect, useState} from 'react'
22

33
import {SxProp} from '../../sx'
44
import {getCharacterCoordinates} from '../utils/character-coordinates'
5+
import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect'
56

67
type UseDynamicTextareaHeightSettings = {
78
disabled?: boolean
@@ -63,7 +64,7 @@ export const useDynamicTextareaHeight = ({
6364
// eslint-disable-next-line react-hooks/exhaustive-deps
6465
}, [minHeightLines, maxHeightLines, value, elementRef, disabled])
6566

66-
useLayoutEffect(refreshHeight, [refreshHeight])
67+
useIsomorphicLayoutEffect(refreshHeight, [refreshHeight])
6768

6869
// With Slots, initial render of the component is delayed and so the initial layout effect can occur
6970
// before the target element has actually been calculated in the DOM. But if we only use regular effects,

src/drafts/hooks/useSafeAsyncCallback.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {useCallback, useEffect, useLayoutEffect, useRef} from 'react'
1+
import {useCallback, useEffect, useRef} from 'react'
2+
import useIsomorphicLayoutEffect from '../../utils/useIsomorphicLayoutEffect'
23

34
export const callbackCancelledResult = Symbol('callbackCancelledResult')
45
export type CallbackCancelledResult = typeof callbackCancelledResult
@@ -27,7 +28,7 @@ export const useSafeAsyncCallback = <A extends unknown[], R>(
2728
allowCallingAfterUnmount = false,
2829
): ((...args: A) => R | CallbackCancelledResult) => {
2930
const trackingRef = useRef(fn)
30-
useLayoutEffect(() => {
31+
useIsomorphicLayoutEffect(() => {
3132
trackingRef.current = fn
3233
}, [fn])
3334

src/hooks/useId.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// eslint-disable-next-line import/no-namespace
1+
// eslint-disable-next-line no-restricted-imports, import/no-namespace
22
import * as React from 'react'
33
// eslint-disable-next-line no-restricted-imports
44
import {useSSRSafeId} from '@react-aria/ssr'

src/utils/useIsomorphicLayoutEffect.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// eslint-disable-next-line no-restricted-imports
12
import {useEffect, useLayoutEffect} from 'react'
23

34
const useIsomorphicLayoutEffect =

0 commit comments

Comments
 (0)