signals icon indicating copy to clipboard operation
signals copied to clipboard

Error when using signals with react-native navigation

Open MohamedJerbi opened this issue 2 years ago • 6 comments

The error is easy to replicate. packadge.json

{
  "name": "",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
  },
  "dependencies": {
    "@preact/signals-react": "^1.2.1",
    "@react-navigation/bottom-tabs": "^6.4.0",
    "@react-navigation/native": "^6.0.13",
    "@react-navigation/native-stack": "^6.9.1",
    "i18next": "^22.0.4",
    "react": "18.1.0",
    "react-i18next": "^12.0.0",
    "react-native": "0.70.3",
    "react-native-gesture-handler": "^2.8.0",
    "react-native-material-dropdown": "^0.11.1",
    "react-native-paper": "^5.0.0-rc.8",
    "react-native-safe-area-context": "^4.4.1",
    "react-native-screens": "^3.16.0",
    "react-native-svg": "^13.4.0",
    "react-native-vector-icons": "^9.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "@tsconfig/react-native": "^2.0.2",
    "@types/jest": "^26.0.23",
    "@types/react": "^18.0.21",
    "@types/react-native": "^0.70.4",
    "@types/react-native-material-dropdown": "^0.11.5",
    "@types/react-test-renderer": "^18.0.0",
    "@typescript-eslint/eslint-plugin": "^5.37.0",
    "@typescript-eslint/parser": "^5.37.0",
    "babel-jest": "^26.6.3",
    "eslint": "^7.32.0",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "0.72.3",
    "react-test-renderer": "18.1.0",
    "typescript": "^4.8.3"
  },
  "jest": {
    "preset": "react-native",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  }
}

How to reproduce.

  1. Setup react-native navigation example
const App = () => (
  <NavigationContainer>
    <Stack.Navigator
      initialRouteName={initialRouteName}
      screenOptions={noHeaderOption}>
      <Stack.Screen name="Login" component={Login} />
    </Stack.Navigator>
  </NavigationContainer>
);

  1. use react signals here I have another file containing an exported signal
import {Signal, signal} from '@preact/signals-react';
import {User} from '../types';

const user: Signal<User> = signal(null);
// get from session storage?

export const initialRouteName = user ? 'BottomTab' : 'Login';

export default user;
 

Once I import this signal inside the Login component and use it there, I get the error Error: A navigator can only contain 'Screen', 'Group' or 'React.Fragment' as its direct children (found 'Screen' for the screen 'Login'). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.


This error is located at:
    in NativeStackNavigator (created by App)
    in EnsureSingleNavigator
    in BaseNavigationContainer
    in ThemeProvider
    in NavigationContainerInner (created by App)
    in App (created by Main)
    in ThemeProvider (created by Provider)
    in RCTView (created by View)
    in View (created by Portal.Host)
    in Portal.Host (created by Provider)
    in Provider (created by Main)
    in Main
    in RCTView (created by View)
    in View (created by AppContainer)
    in RCTView (created by View)
    in View (created by AppContainer)
    in AppContainer
    in thedoc(RootComponent), js engine: hermes

MohamedJerbi avatar Oct 31 '22 22:10 MohamedJerbi

I am running into this same error.

elliotwaite avatar Nov 05 '22 11:11 elliotwaite

same here..

Seanmclem avatar Nov 13 '22 01:11 Seanmclem

This issues happens in react-navigation as well I've disabled these lines and it works as expected. at this file File

// React.createElement = WrapJsx(React.createElement);
// JsxDev.jsx && /*   */ (JsxDev.jsx = WrapJsx(JsxDev.jsx));
// JsxPro.jsx && /*   */ (JsxPro.jsx = WrapJsx(JsxPro.jsx));
// JsxDev.jsxs && /*  */ (JsxDev.jsxs = WrapJsx(JsxDev.jsxs));
// JsxPro.jsxs && /*  */ (JsxPro.jsxs = WrapJsx(JsxPro.jsxs));
// JsxDev.jsxDEV && /**/ (JsxDev.jsxDEV = WrapJsx(JsxDev.jsxDEV));
// JsxPro.jsxDEV && /**/ (JsxPro.jsxDEV = WrapJsx(JsxPro.jsxDEV));

So, I suggest to disable these lines at ios and android platforms. @JoviDeCroock

mustafaskyer avatar Feb 01 '23 23:02 mustafaskyer

Facing the same issue with a BottomTabNavigator in React Native. Disabling the lines as mentioned above didnt work for me either.

raphaelott avatar Feb 27 '23 09:02 raphaelott

Facing the same problem.

suman379 avatar Mar 07 '23 07:03 suman379

I fixed this issue (it works for 1.2.1 version). You need to apply this patch for @react-navigation/core:

diff --git a/node_modules/@react-navigation/core/src/Group.tsx b/node_modules/@react-navigation/core/src/Group.tsx
index 352ba31..893d2c2 100644
--- a/node_modules/@react-navigation/core/src/Group.tsx
+++ b/node_modules/@react-navigation/core/src/Group.tsx
@@ -12,3 +12,4 @@ export default function Group<
   /* istanbul ignore next */
   return null;
 }
+Group.__isGroup = true;
\ No newline at end of file
diff --git a/node_modules/@react-navigation/core/src/Screen.tsx b/node_modules/@react-navigation/core/src/Screen.tsx
index 4ca4306..f116e61 100644
--- a/node_modules/@react-navigation/core/src/Screen.tsx
+++ b/node_modules/@react-navigation/core/src/Screen.tsx
@@ -15,3 +15,4 @@ export default function Screen<
   /* istanbul ignore next */
   return null;
 }
+Screen.__isScreen = true;
\ No newline at end of file
diff --git a/node_modules/@react-navigation/core/src/useNavigationBuilder.tsx b/node_modules/@react-navigation/core/src/useNavigationBuilder.tsx
index 76442df..e1c8632 100644
--- a/node_modules/@react-navigation/core/src/useNavigationBuilder.tsx
+++ b/node_modules/@react-navigation/core/src/useNavigationBuilder.tsx
@@ -93,7 +93,7 @@ const getRouteConfigsFromChildren = <
     ScreenConfigWithParent<State, ScreenOptions, EventMap>[]
   >((acc, child) => {
     if (React.isValidElement(child)) {
-      if (child.type === Screen) {
+      if (child.type?.__isScreen) {
         // We can only extract the config from `Screen` elements
         // If something else was rendered, it's probably a bug
 
@@ -121,7 +121,7 @@ const getRouteConfigsFromChildren = <
         return acc;
       }
 
-      if (child.type === React.Fragment || child.type === Group) {
+      if (child.type === React.Fragment || child.type?.__isGroup) {
         if (!isValidKey(child.props.navigationKey)) {
           throw new Error(
             `Got an invalid 'navigationKey' prop (${JSON.stringify(

Voznov avatar Apr 14 '23 13:04 Voznov