undefined is not an object react navigation from doc - react-native

I have this code that come directly from the doc of react navigation link here.
import * as React from 'react';
import { Button } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Jane' })
}
/>
);
};
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
const App = () => {
return (
<NavigationContainer>
<HomeScreen />
</NavigationContainer>
);
};
export default App;
and when i click on the button i have this error : undefined is not an object. can you help me found what's wrong ?
That just to test at the end i want different page in my app and navigate into,
i don't understant why all the different page is on the same file ...
Thank you,
have good coding day

The Reason Behind this is you are used HomeScreen component inside App component.You Have to use MyStack component inside the App component.
then you get error about NavigationContainer you have to use NavigationContainer one time not in nested.Please remove NavigationContainer from App component or MyStack component.
also Add ..
import{Text} from 'react-native';
congratulations Your Programm run perfectly.
I Changed small things in your code please copy and then try it will work.
import * as React from 'react';
import { Button,Text} from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const Stack = createNativeStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Jane' })
}
/>
);
};
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
const App = () => {
return (
<MyStack />
);
};
export default App;
Happy Coding

Related

The action 'NAVIGATE' with payload {} was not handled by any navigator

Have a problem with navigation module in an app. Cannot understand what's wrong, maybe that's my inattention or i know not enough.
This one is NewsRoot.tsx
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { NewsScreen } from "./News";
const Stack = createNativeStackNavigator();
export const NewsRoot = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="News">
<Stack.Screen
name="News"
component={NewsScreen}
options={{
headerTitle: "News",
headerTintColor: "#fff"}} />
</Stack.Navigator>
</NavigationContainer>
);
};
This one is for button with link:
export const TopScreen = ({ navigation }: any) => {
///...
<Press onPress={() => navigation.navigate("News")}><LCText>To News </LCText></Press>
///...
}
When i try to press the button, then nothing happens and console logs error:
The action 'NAVIGATE' with payload {"name":"News"} was not handled by any navigator.

How to join 2 stack navigators in React Native

I have 2 stack navigators that handles 2 diferrent slices of my app, one will be the authentication and the other will be the app itself. I would like to put these 2 stack navigators in different files and one file to join both. Is there a way to do this?
MainNavigation code
import React from 'react'
import {NavigationContainer} from '#react-navigation/native'
import AuthNav from './AuthNav'
import AppNav from './AppNav'
const MainNav = () => {
return (
<NavigationContainer>
<AuthNav />
<AppNav />
</NavigationContainer>
)
}
export default MainNav
AppNavigation code
const Stack = createStackNavigator<AppNavParams>()
const AppNav = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Register">
{props => <RegisterScreen {...props} />}
</Stack.Screen>
</Stack.Navigator>
)
}
AuthNavigation Code
const Stack = createStackNavigator<AppNavParams>()
const AuthNav = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Login">
{props => <RegisterScreen {...props} />}
</Stack.Screen>
</Stack.Navigator>
)
}
edit1: removed image and inserted code
You just need to verify if your authenticated token exist or not, in your MainNav
And create a stack navigator around both AppNav and AuthNav
You can do something like this
import React, { useState, useEffect, useRef } from 'react'
import { NavigationContainer, useLinking } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
import AppNav from './AppNav'
import AuthNav from './AuthNav'
const AppStack = createStackNavigator()
const MainNav() => {
const someFn = () => {
// write your logic here. Either retrieve from redux store or from local storage
// return true or false
}
const isLoggedIn = someFn()
return (
<NavigationContainer>
<AppStack.Navigator>
{isLoggedIn ? (
<AppStack.Screen name='App' component={AppNav} />
) : (
<AppStack.Screen name='Auth' component={AuthNav} />
)}
</AppStack.Navigator>
</NavigationContainer>
)
}
You need to create an auth stack and user stack and render based on sign state.
Create your auth stack.
const Stack = createStackNavigator();
export default function AuthStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
</Stack.Navigator>
);
}
Create your user stack.
const Stack = createStackNavigator();
export default function UserStack() {
return (
<Stack.Navigator>
<Stack.Screen name="User" component={UserScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
);
}
Render auth or user based on sign state.
export default function Account({ navigation, route }) {
const [sign, setSign] = useState(false);
useEffect(() => {
// some logic to check user sign
}, []);
if (sign) {
return <UserStack />;
} else {
return <AuthStack />;
}
}
Wrap with navigation container
<NavigationContainer>
<Account/>
</NavigationContainer>

Open the drawer when I click the icon react navigation version 5

I want to open the drawer when I click the icon in the headerLeft part, I also have try to this.props.navigation.dispatch but is gives an error also navigation.dispatch gives error
The code below does not gives errors but is does not open the drawer
import { DrawerActions } from '#react-navigation/native';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
export default class App extends Component {
createHomeStack = () =>
<Stack.Navigator>
<Stack.Screen
initialRouteName="login"
headerMode="screen"
name="main"
children={ this.createBottomTabs}
options={{
title: "Fitbit",
headerLeft: () => (
<Icon
name="menu"
size={25}
color="#D4AF37"
onPress={() => {DrawerActions.openDrawer() }}
/>
)} } />
</Stack.Navigator>
createDrawer = ({navigation}) =>
<Drawer.Navigator initialRouteName="Main" >
<Drawer.Screen name="Main" component={Main} />
<Drawer.Screen name="Contacts" component={Food} />>
</Drawer.Navigator>
render() {
return (
<NavigationContainer>
{this.createHomeStack()}
</NavigationContainer>
);
}
}
In order to achieve that you need to wrap the stack into the drawer as the documentation says.
Documentation here
I would probably use something like this:
EDIT:
Added full code
import React,{Component} from 'react'
import { NavigationContainer } from '#react-navigation/native'
import { createDrawerNavigator } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack'
import { View } from 'react-native'
import Icon from 'react-native-vector-icons/dist/Feather'
const Drawer = createDrawerNavigator()
const Stack = createStackNavigator()
const Main = () => <View></View>
const Food = () => <View></View>
const Home = ({ navigation }) => (
<Stack.Navigator>
<Stack.Screen name="Main" component={Main} options={{
headerLeft: () => <Icon
name="menu"
size={25}
color="#D4AF37"
onPress={() => navigation.openDrawer()}
/>
}} />
</Stack.Navigator>
)
const DrawerNavigator = () => (
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Contacts" component={Food} />
</Drawer.Navigator>
)
export default props => (
<NavigationContainer>
<DrawerNavigator />
</NavigationContainer>
)
You need To import DrawerActions
import {DrawerActions } from '#react-navigation/native';
And You Can Open Using
navigation.dispatch(DrawerActions.openDrawer());

How to use navigation.navigate from a component outside the stack.navigation

I have an application using React native where I am using react-navigation (5.2.9).
I built a Stack.Navigator where I've got my screens but I want the Footer component to be outside so it renders in all screens. The problem is, I can't navigate from the footer, which is what I need to do as the footer has a few buttons that should be changing the screen:
const Stack = createStackNavigator();
const App = () => {
return (
<Provider store={store}>
<NavigationContainer>
<Header />
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerShown: false
}}
/>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{
headerShown: false
}}
/>
</Stack.Navigator>
<Footer />
</NavigationContainer>
</Provider>
);
};
How do I pass the navigation prop to the footer component?
Try this:
Create a new file named: RootNavigation.js
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
// file where you have the navigation
import {navigationRef} from './path/to/RootNavigation';
<NavigationContainer ref={navigationRef}>
.....
<Footer />
</NavigationContainer>
And Footer.js should be something like this:
// Footer.js
import React from 'react';
import {View, Button} from 'react-native';
import * as RootNavigation from './path/to/RootNavigation';
const Footer= () => {
return (
<View>
<Button
title={'Go to'}
onPress={() =>
RootNavigation.navigate('screenName ', {userName: 'Lucy'})
}
/>
</View>
);
};
export default Footer;
For more info you can read the documentation. https://reactnavigation.org/docs/navigating-without-navigation-prop/
The components outside of the Stack.Screen components do not receive the navigation prop. So in this case, you have to get the NavigationContainer using refs in your footer component, as follows:
Create a ref with const myRef = React.createRef()
pass it to the <NavigationContainer ref={myRef}>, and
use that ref to navigate, myRef.current?.navigate(name, params).
It is all explained here. The docs here separate the creation of the ref in a new file, to allow you to import the ref without dependency loops/ issues. As the docs state, you can now call RootNavigation.navigate('ChatScreen', { userName: 'Lucy' }); in any js module, not just in a react component.
In your case though, you don't need the ref in separate file.
const Stack = createStackNavigator();
const navigationRef = React.createRef();
const App = () => {
return (
<Provider store={store}>
<NavigationContainer ref={navigationRef}>
<Header />
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerShown: false
}}
/>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{
headerShown: false
}}
/>
</Stack.Navigator>
<Footer navigationRef={navigationRef}/>
</NavigationContainer>
</Provider>
);
};
And in <Footer/> use navigationRef.current?.navigate(name, params)
From the documentation.
https://reactnavigation.org/docs/connecting-navigation-prop/
import * as React from 'react';
import { Button } from 'react-native';
import { useNavigation } from '#react-navigation/native';
function GoToButton({ screenName }) {
const navigation = useNavigation();
return (
<Button
title={`Go to ${screenName}`}
onPress={() => navigation.navigate(screenName)}
/>
);
}
I ended up building a component called screen that will just wrap the content of screen and render the header/footer based on props:
import React from 'react';
import { View } from 'native-base';
import style from './style';
import Footer from '../../footer';
import Header from '../../header';
const Screen = ({
footer,
header,
children,
navigation
}) => (
<View style={style.screen}>
{ header && <Header navigation={navigation} />}
{ children }
{ footer && <Footer navigation={navigation} />}
</View>
);
export default Screen;
And wrapping the screens of my apps like this:
<Screen header footer navigation={navigation}>
... screen content
</Screen>
I feel like it is the best way if I can't sort that problem out.
A simple trick to extract navigation out of screenOptions.
function NavWrapper() {
const navigatorRef = useRef<any>();
<Tab.Navigator
screenOptions={({ navigation: nav }) => navigatorRef.current = nav}
>
<Tab.Screen name="screen1" />
</Tab.Navigator>
}
I solve this problem with a global state using React context API:
// When enter in the HomeScreen:
const { setGlobalNavigation, globalNavigation } = useGlobalContext();
const navigation = useNavigation<RemindersNavigationProp>();
useEffect(() => {
if (setGlobalNavigation && !globalNavigation) setGlobalNavigation(navigation);
}, [setGlobalNavigation, globalNavigation, navigation]);
// When want to use:
const { globalNavigation } = useGlobalContext();
const handleNavigate = () =>
globalNavigation.navigate("contactsStack", { screen: "newContact" });

react-navigate v5 and API. Couldn't find a 'component' or 'children' prop for the screen 'Home'

I took a simple example of NavigationContainer. I have a main Screen <Tab.Screen name="Home" component={HomeScreen} />
I created a new Component HomeScreen then connected with App.js
In my component HomeScreen I fetch data.
I does not work. My error:
Couldn't find a 'component' or 'children' prop for the screen 'Home'. This can happen if you passed 'undefined'.
How could I do it? Thanks!
App.js
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { HomeScreen } from './src/screens/HomeScreen';
import { SignInScreen } from './src/screens/SignInScreen';
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SignInScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
HomeScreen.js
import React, { useEffect, useState } from 'react';
import { ActivityIndicator, FlatList, Text, View } from 'react-native';
export default HomeScreen = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://reactnative.dev/movies.json')
.then((response) => response.json())
.then((json) => setData(json.movies))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
});
return (
<View style={{ flex: 1, padding: 24 }}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Text>{item.title}, {item.releaseYear}</Text>
)}
/>
)}
</View>
);
};
you are exporting default export default HomeScreen but importing with destructing.
Change
import { HomeScreen } from './src/screens/HomeScreen';.
To
import HomeScreen from './src/screens/HomeScreen';