react-native-gesture-handler icon indicating copy to clipboard operation
react-native-gesture-handler copied to clipboard

useLayoutEffect error on the terminal

Open deouws opened this issue 9 months ago • 11 comments

Description

λ ERROR Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.%s GestureDetector (node_modules/react-native-gesture-handler/lib/commonjs/handlers/gestures/GestureDetector/index.js:76:47) DraggableBox (app/index.tsx:14:35) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) onScroll (node_modules/react-native-web/dist/exports/ScrollView/ScrollViewBase.js:57:23) ScrollView (node_modules/react-native-web/dist/exports/ScrollView/index.js:33:4) Route (node_modules/expo-router/build/Route.js:52:17) route (node_modules/expo-router/build/useScreens.js:128:4) StaticContainer (node_modules/@react-navigation/core/lib/commonjs/StaticContainer.js:14:15) EnsureSingleNavigator (node_modules/@react-navigation/core/lib/commonjs/EnsureSingleNavigator.js:19:2) SceneView (node_modules/@react-navigation/core/lib/commonjs/SceneView.js:20:2) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) AnimatedHeaderHeightProvider (node_modules/@react-navigation/native-stack/lib/commonjs/views/NativeStackView.js:117:2) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) (node_modules/react-native-web/dist/vendor/react-native/Animated/createAnimatedComponent.js:25:44) Background (node_modules/@react-navigation/elements/lib/commonjs/Background.js:14:2) Screen (node_modules/@react-navigation/elements/lib/commonjs/Screen.js:19:69) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) SafeAreaProviderCompat (node_modules/@react-navigation/elements/lib/commonjs/SafeAreaProviderCompat.js:36:2) NativeStackView (node_modules/@react-navigation/native-stack/lib/commonjs/views/NativeStackView.js:17:2) PreventRemoveProvider (node_modules/@react-navigation/core/lib/commonjs/PreventRemoveProvider.js:38:2) NavigationContent (node_modules/@react-navigation/core/lib/commonjs/useComponent.js:12:2) children (node_modules/@react-navigation/core/lib/commonjs/useComponent.js:28:4) NativeStackNavigator (node_modules/@react-navigation/native-stack/lib/commonjs/navigators/createNativeStackNavigator.js:14:2) userDefinedChildren (node_modules/expo-router/build/layouts/withLayoutContext.js:75:62) Route (node_modules/expo-router/build/Route.js:52:17) route (node_modules/expo-router/build/useScreens.js:128:4) hrefAttrs (node_modules/react-native-web/dist/exports/View/index.js:35:24) NativeSafeAreaProvider (node_modules/react-native-safe-area-context/lib/commonjs/NativeSafeAreaProvider.web.js:29:2) SafeAreaProvider (node_modules/react-native-safe-area-context/lib/commonjs/SafeAreaContext.js:28:2) Html (node_modules/expo-router/build/static/html.js:23:16) wrapper (node_modules/expo-router/build/static/renderStaticContent.js:66:24) wrapper (node_modules/expo-router/build/ExpoRoot.js:53:23) ThemeProvider (node_modules/@react-navigation/core/lib/commonjs/theming/ThemeProvider.js:13:2) EnsureSingleNavigator (node_modules/@react-navigation/core/lib/commonjs/EnsureSingleNavigator.js:19:2) BaseNavigationContainer (node_modules/@react-navigation/core/lib/commonjs/BaseNavigationContainer.js:79:2) NavigationContainerInner (node_modules/expo-router/build/fork/NavigationContainer.js:32:36) ContextNavigator (node_modules/expo-router/build/ExpoRoot.js:73:28) ExpoRoot (node_modules/expo-router/build/ExpoRoot.js:47:29) AppContainer (../shim:react-native-web/dist/exports/AppRegistry/AppContainer.js:4:24) ServerContainer (node_modules/@react-navigation/native/lib/commonjs/ServerContainer.js:21:2) λ Bundled 628ms node_modules/expo-router/node/render.js (874 modules) Web Bundled 1268ms node_modules/expo-router/entry.js (983 modules) Web Bundled 265ms node_modules/expo-router/entry.js (933 modules) LOG [web] Logs will appear in the browser console

Steps to reproduce

https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/simple/draggable/index.tsx

The above code was used in react-native app

Snack or a link to a repository

https://github.com/deouws/testGesture.git

Gesture Handler version

2.21.2

React Native version

0.76.2

Platforms

Web

JavaScript runtime

None

Workflow

None

Architecture

None

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

deouws avatar Feb 03 '25 21:02 deouws

https://snack.expo.dev/@deouws/frowning-yellow-bananas

deouws avatar Feb 03 '25 21:02 deouws

Please have a look at the below repository https://github.com/deouws/testGesture.git

deouws avatar Feb 03 '25 22:02 deouws

Hey, please let me know if this PR fixes this issue for you

latekvo avatar Feb 06 '25 12:02 latekvo

Hello , what should be the step to test the fixes on https://github.com/deouws/testGesture.git. ?

Thank you

deouws avatar Feb 06 '25 14:02 deouws

@deouws let me know if the following steps work:

Open your terminal and navigate to your testGesture app:

  • cd path/to/testGesture

Then enter the parent directory:

  • cd ..

Clone the react-native-gesture-handler repo:

  • git clone https://github.com/software-mansion/react-native-gesture-handler/

Enter the Gesture Handler, the checkout to the branch with the fix:

  • git checkout @latekvo/fix-ssr-layout-effect-warning

By now here is how your file structure should look like:

- parent_directory/
   - react-native-gesture-handler/
   - testGesture/

Then navigate back to testGesture, and add the cloned repo as your react-native-gesture-handler package:

  • cd ../testGesture
  • yarn add ../react-native-gesture-handler

If the yarn add command fails (it shouldn't), go back to the Gesture Handler directory, run npm pack, then yarn add the file that will be generated by npm pack instead of adding the entire Gesture Handler directory.

latekvo avatar Feb 10 '25 16:02 latekvo

Running into the same issue, i changed the code in my node_modules/react-native-gesture-handler/lib/commonjs/handlers/gestures/GestureDetector/index.js to have useSafeLayoutEffect as in the PR linked and it gets rid of that error.

nmpereira avatar Mar 06 '25 16:03 nmpereira

Im not able to test via the instructions above as i get an error, but thats likely because of how Im building it

Logs for your project will appear below. Press Ctrl+C to exit.
λ Bundling failed 1273ms node_modules/expo-router/node/render.js (1241 modules)
Web Bundling failed 1278ms node_modules/expo-router/entry.js (1456 modules)

Metro error: Unable to resolve module ../../react-native-gesture-handler from /<>/<>/<>/<myapp>/app/_layout.tsx: 

None of these files exist:
  * ../react-native-gesture-handler(.web.ts|.ts|.web.tsx|.tsx|.web.js|.js|.web.jsx|.jsx|.web.json|.json|.web.cjs|.cjs|.web.mjs|.mjs|.web.scss|.scss|.web.sass|.sass|.web.css|.css|.web.css|.css)
  * ../react-native-gesture-handler
  12 | import React from "react";
  13 | import Header from "@/components/Header";
> 14 | import { GestureHandlerRootView } from '../../react-native-gesture-handler';

From my manual change in my own node_modules, it works perfectly

nmpereira avatar Mar 06 '25 16:03 nmpereira

Sorry for late update. Here is the error I am getting when followed the steps advised earlier

Server Error While trying to resolve module react-native-gesture-handler from file /private/tmp/testGesture/app/index.tsx, the package /private/tmp/testGesture/node_modules/react-native-gesture-handler/package.json was successfully found. However, this package itself specifies a main module field that could not be resolved (/private/tmp/testGesture/node_modules/react-native-gesture-handler/lib/commonjs/index.js. Indeed, none of these files exist:

  • /private/tmp/testGesture/node_modules/react-native-gesture-handler/lib/commonjs/index.js(.web.ts|.ts|.web.tsx|.tsx|.web.js|.js|.web.jsx|.jsx|.web.json|.json|.web.cjs|.cjs|.web.mjs|.mjs|.web.scss|.scss|.web.sass|.sass|.web.css|.css)
  • /private/tmp/testGesture/node_modules/react-native-gesture-handler/lib/commonjs/index.js/index(.web.ts|.ts|.web.tsx|.tsx|.web.js|.js|.web.jsx|.jsx|.web.json|.json|.web.cjs|.cjs|.web.mjs|.mjs|.web.scss|.scss|.web.sass|.sass|.web.css|.css) Source

deouws avatar Mar 06 '25 20:03 deouws

Hey, just a heads-up, the PR with the fix is likely flawed - we're using useLayoutEffect instead of useEffect in order to fix a react-freeze bug. Replacing the useLayoutEffect with useEffect might reintroduce that react-freeze issue. I'll look into this further.


Regarding applying the fix, the following method is simpler:

If you're using npm:

  • npm install "https://github.com/software-mansion/react-native-gesture-handler.git#@latekvo/fix-ssr-layout-effect-warning" --save

If you're using yarn:

  • yarn add react-native-gesture-handler@software-mansion/react-native-gesture-handler#@latekvo/fix-ssr-layout-effect-warning

That's all the installation steps, the app should have the PR applied after running one of these commands.

latekvo avatar Mar 06 '25 22:03 latekvo

From what i understand, useLayoutEffect works on react-native mobile, but on react-native-web, it shows an error. Im not sure why but a couple of libraries I'm using for react-native are showing this error. Currently I'm seeing the same error with https://github.com/gorhom/react-native-bottom-sheet as well which hasnt patched it (I'll open the same issue on there as well!).

However, gluestack seems to have patched it https://github.com/gluestack/gluestack-ui/blob/main/packages/styled/react/src/hooks/useSafeLayoutEffect.ts#L3

Im seeing the same fix in multiple issue threads

  • https://github.com/react-component/overflow/issues/6#issuecomment-819215239
  • https://medium.com/@alexandereardon/uselayouteffect-and-ssr-192986cdcf7a

Disclaimer: I'm sorta new to react-native (and react), so i dont fully understand how this works, but from my research above, it seems like condiionally patching the useLayoutEffect to use useEffect based on where it's running is the way to go. I'm just not sure about the side effects of patching it. For now, im fine with using the PR fix as a workaround!

Thoughts?

nmpereira avatar Mar 07 '25 23:03 nmpereira

Hey, in majority of cases, the useLayoutEffect cannot be trivially replaced by useEffect as both of these hooks serve a different purpose. What useIsomorphicEffect or useSafeEffect patches are doing is exactly that simple replacement. As I said, I'll look into the exact issue more, as it all depends on whether the react-freeze bug persists with SSR or not. It's likely we'll have to work around using useLayoutEffect, as simply replacing it with useEffect might just hide reintroduction of the react-freeze bug.

latekvo avatar Mar 08 '25 00:03 latekvo