Skip to content

Commit ff83c88

Browse files
authored
Fix SSR error with useLayoutEffect (#3752)
## Description Using `useLayoutEffect` in combination with SSR results in a warning. This PR adds [isomorphicLayoutEffect](https://github.com/reduxjs/react-redux/blob/7e2fdd4ee2021e4282e12ba9fc722f09124e30cd/src/utils/useIsomorphicLayoutEffect.ts#L36), which acts as a `useEffect` when running on server and as `useLayoutEffect` everywhere else. This fixes #3375. Note: This may cause #2920 to happen when running SSR, however as we couldn't replicate the issue on main, probably due to same changes to view recycling within react native, I think it would even be ok to simply revert #2925, and simply only `useEffect`, so it shouldn't be an issue. I decided to use `isomorphicLayoutEffect` instead of reverting to ensure correctness. ## Test plan See that there is no warning mentioned in #3375
1 parent fbcdaaa commit ff83c88

2 files changed

Lines changed: 22 additions & 10 deletions

File tree

  • packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector

packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/index.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
/* eslint-disable react/no-unused-prop-types */
2-
import React, {
3-
useContext,
4-
useEffect,
5-
useLayoutEffect,
6-
useMemo,
7-
useRef,
8-
} from 'react';
2+
import React, { useContext, useEffect, useMemo, useRef } from 'react';
93
import { Platform } from 'react-native';
104
import findNodeHandle from '../../../findNodeHandle';
115
import { GestureType } from '../gesture';
@@ -19,7 +13,7 @@ import { useAnimatedGesture } from './useAnimatedGesture';
1913
import { attachHandlers } from './attachHandlers';
2014
import { needsToReattach } from './needsToReattach';
2115
import { dropHandlers } from './dropHandlers';
22-
import { useWebEventHandlers } from './utils';
16+
import { useIsomorphicLayoutEffect, useWebEventHandlers } from './utils';
2317
import { Wrap, AnimatedWrap } from './Wrap';
2418
import { useDetectorUpdater } from './useDetectorUpdater';
2519
import { useViewRefHandler } from './useViewRefHandler';
@@ -149,7 +143,7 @@ export const GestureDetector = (props: GestureDetectorProps) => {
149143

150144
useAnimatedGesture(preparedGesture, needsToRebuildReanimatedEvent);
151145

152-
useLayoutEffect(() => {
146+
useIsomorphicLayoutEffect(() => {
153147
const viewTag = findNodeHandle(state.viewRef) as number;
154148
preparedGesture.isMounted = true;
155149

packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
} from '../../gestureHandlerCommon';
2020
import { isNewWebImplementationEnabled } from '../../../EnableNewWebImplementation';
2121
import { RNRenderer } from '../../../RNRenderer';
22-
import { useCallback, useRef, useState } from 'react';
22+
import React, { useCallback, useRef, useState } from 'react';
2323
import { Reanimated } from '../reanimatedWrapper';
2424
import { onGestureHandlerEvent } from '../eventReceiver';
2525
import { WebEventHandler } from './types';
@@ -179,3 +179,21 @@ export function useWebEventHandlers() {
179179
: undefined,
180180
});
181181
}
182+
183+
// code below is modified version of the code found in:
184+
// https://github.com/reduxjs/react-redux/blob/7e2fdd4ee2021e4282e12ba9fc722f09124e30cd/src/utils/useIsomorphicLayoutEffect.ts#L36
185+
// React currently throws a warning when using useLayoutEffect on the server.
186+
// To get around it, we can conditionally useEffect on the server (no-op) and
187+
// useLayoutEffect in the browser.
188+
const isDOM = !!(
189+
typeof window !== 'undefined' &&
190+
typeof window.document !== 'undefined' &&
191+
typeof window.document.createElement !== 'undefined'
192+
);
193+
194+
// Under React Native, we know that we always want to use useLayoutEffect
195+
const isReactNative =
196+
typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
197+
198+
export const useIsomorphicLayoutEffect =
199+
isDOM || isReactNative ? React.useLayoutEffect : React.useEffect;

0 commit comments

Comments
 (0)