How do I pass a state object to a screen in React Native? - reactjs

** i want to pass the setScreen object to Signup screen
please tell me how do i pass it so i could change the screen state from Signup screen**
import React, { useState } from 'react';
import 'react-native-gesture-handler';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import AccountScreen from './src/screens/AccountScreen';
import SigninScreen from './src/screens/SigninScreen';
import SignupScreen from './src/screens/SignupScreen';
import TrackCreateScreen from './src/screens/TrackCreateScreen';
import TrackDetailScreen from './src/screens/TrackDetailScreen';
import TrackListScreen from './src/screens/TrackListScreen';
const Stack = createStackNavigator();
const TrackStack = createStackNavigator();
const Tab = createBottomTabNavigator();
const TrackScreenStack = () => {
return (
<TrackStack.Navigator initialRouteName="TrackList">
<TrackStack.Screen
name="TrackList"
component={TrackListScreen}
/>
<TrackStack.Screen
name="TrackDetail"
component={TrackDetailScreen}
/>
</TrackStack.Navigator>
)
}
** here i have declared the state object
and i wish to pass it in Signup screen
so that i could switch between screen stacks**
const App = () => {
const [screen, setScreen] = useState(true);
return (
<NavigationContainer>
{screen ? (
<Stack.Navigator initialRouteName="Signup">
<Stack.Screen
name="Signup"
component={SignupScreen}
/>
<Stack.Screen
name="Signin"
component={SigninScreen}
/>
</Stack.Navigator>
) :
<Tab.Navigator>
<Tab.Screen
name="Track"
component={TrackScreenStack}
/>
<Tab.Screen
name="Account"
component={AccountScreen}
/>
<Tab.Screen
name="TrackCreate"
component={TrackCreateScreen}
/>
</Tab.Navigator>
}
</NavigationContainer>
)
}
export default App;

Related

React Navigation: TypeError: undefined is not an object (evaluating 'navigation.navigate') Issue

Facing issues while using react-navigation navigation.navigate functions.
TypeError: undefined is not an object (evaluating
'navigation.navigate')
import React from "react";
import { AccountBackground, AccountCover, Title} from "../components/account.styles";
import { MaterialIcons } from "#expo/vector-icons";
export const AccountScreen = ({ navigation }) => {
setTimeout(() => { navigation.navigate("Login");}, 3000);
return (
<AccountBackground>
<AccountCover />
<Title>Meals To Go</Title>
<MaterialIcons name="navigate-next" size={48} color="black" />
</AccountBackground>
);
};
import React, { useState, useEffect } from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { AccountScreen } from "../../features/account/screens/account.screen";
import { LoginScreen } from "../../features/account/screens/login.screen";
import { RegisterScreen } from "../../features/account/screens/register.screen";
const Stack = createStackNavigator();
const createScreenOptions = { headerShown: false };
export const AccountNavigator = () => {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={createScreenOptions}>
<Stack.Screen name="Main" component={AccountScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
</Stack.Navigator>
</NavigationContainer>
);};

How to navigate to a page in other navigator in other file in React-native?

some people and I made an app with react native to practice, and later it turned out that we used two different navigators.
I tried to combine but I failed, and tried to google but couldn't find any satisfying answer.
I just want to call SplashScreen after signing out.
so here is the code for the initial screens including Auth aka SplashScreen:
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import Auth from './../screens/Auth'
...
import Welcome from './../screens/Welcome'
import MainApp from './MainApp' //this contains signout page
const Stack = createNativeStackNavigator();
const RootStack = () => {
return(
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown:false}
}}
initialRouteName="Auth"
>
<Stack.Screen name= "Auth" component={Auth} />
...
<Stack.Screen />
<Stack.Screen name="MainApp" component={MainApp}/>
</Stack.Navigator>
</NavigationContainer>
)
and here is the code with my information and signout:
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Stack=createStackNavigator()
const HomeScreenOptions={
headerStyle:{backgroundColor:'lightblue'},
headerTitleStyle:{color:'black', justifyContent:'center'},
headerTintColor:'white',
}
const Tabs = createBottomTabNavigator();
const YourwordsStack = createStackNavigator();
const HomeStack = createStackNavigator();
const MyInfoStack = createStackNavigator();
const YourwordsStackScreen =()=>(
<YourwordsStack.Navigator screenOptions={HomeScreenOptions}>
<YourwordsStack.Screen name="Yourwords" component={YourwordsScreen}/>
</YourwordsStack.Navigator>
)
const HomeStackScreen =()=>(
<HomeStack.Navigator
screenOptions={HomeScreenOptions}
>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Yourwords" component={YourwordsScreen} />
<HomeStack.Screen name="Mywords" component={MywordsScreen}/>
</HomeStack.Navigator>
)
const MyInfoStackScreen =()=>(
<MyInfoStack.Navigator screenOptions={HomeScreenOptions}>
<MyInfoStack.Screen name="MyInfo" component={MyInfoScreen}/> // this page needs to be connected with Auth
<MyInfoStack.Screen name="MyWordsHistory" component={MyWordsHistory}/>
<MyInfoStack.Screen name="MyMessages" component={MyMessages}/>
</MyInfoStack.Navigator>
)
export default function MainApp({navigation}) {
return (
<NavigationContainer independent={true}>
<Tabs.Navigator
initialRouteName="HomeTab"
screenOptions={{
tabBarHideOnKeyboard:true,
tabBarStyle:[
{
display:'flex'
},
null
]
}}
>
<Tabs.Screen
name="YourwordsTab"
component={YourwordsStackScreen}
options={{
headerShown:false,
}}
/>
<Tabs.Screen
name="HomeTab"
component={HomeStackScreen}
options={{
headerShown:false,
}}
/>
<Tabs.Screen
name="MyInfoTab"
component={MyInfoStackScreen}
options={{
headerShown:false,
}}
/>
</Tabs.Navigator>
</NavigationContainer>
)
}
so the first problem is that we used different Navigators
and the second problem is that we can't really link a page to another one through different file.
how can I solve this?

Passing navigation to component

I'm trying to pass the navigation -- using React Navigation 5 -- to my component in my stackNavigation. Here's my code:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { useNavigation } from '#react-navigation/native';
const MyStack = new createStackNavigator();
const MyStackNav = () => {
const navigation = useNavigation();
return(
<MyStack.Navigator screenOptions={{ headerShown: false }}>
<MyStack.Screen name="Comp1" component={Component1} />
<MyStack.Screen name="Comp2" component={Component2} />
</MyStack.Navigator>
);
}
export default MyStackNav;
I tried this but got an error:
<MyStack.Screen name="Comp1" component={(navigation) => <Component1 navigation={navigation} />} />
How do I pass navigation to my components i.e. Component1 and Component2. By the way, those are class components.
You should import NavigationContainer from #react-navigation/native. Every component within MyStack.Screen will receive a prop navigation.
Example from documentation:
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>{/* ... */}</Stack.Navigator>
</NavigationContainer>
);
}

Testing: react-native (expo) take snapshot of a Screen component inside of react-navigation

My test attempt currently looks like this:
import React from "react"
import { NavigationContainer } from "#react-navigation/native"
import { createStackNavigator } from "#react-navigation/stack"
import { render, waitFor } from "#testing-library/react-native"
import { Provider } from "react-redux"
import { createStore } from "redux"
import rootReducer from "src/store/reducers/root-reducer"
import ProfileScreen from "src/screens/profile"
const store = createStore(rootReducer)
test("renders correctly", async () => {
const Screen = () => {
// const navigationRef = React.useRef(null) // cause "Invalid hook call. Hooks can only be called inside .."
const Stack = createStackNavigator()
return (
<Provider store={store}>
<NavigationContainer
// ref={navigationRef} // cause "Invalid hook call. Hooks can only be called inside .."
>
<Stack.Navigator>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
</Provider>
)
}
const tree = render(<Screen />)
await waitFor(async () => expect(tree.toJSON()).toMatchSnapshot())
})
But it keeps throwing this:
...
console.error
The above error occurred in the <ForwardRef(NavigationContainer)> component:
in Provider (created by Screen)
in Screen
Consider adding an error boundary to your tree to customize error handling behavior.
Visit <fb link> to learn more about error boundaries
...
I can't find any useful docs/examples on the react-navigation site regrading testing a screen. (I also googled a lot around)
I can try to boil down the code to something like this:
App.json
...
export default function App() {
...
return (
<Provider store={store}>
<Navigation />
</Provider>
)
}
Navigation.js
import React from "react"
import { NavigationContainer, DarkTheme } from "#react-navigation/native"
import { createStackNavigator } from "#react-navigation/stack"
import BottomTabNavigator from "./BottomTabNavigator"
export default function Navigation() {
const navigationRef = React.useRef(null)
return (
<NavigationContainer
theme={DarkTheme}
ref={navigationRef} // https://reactnavigation.org/docs/navigation-container/#ref
>
<RootNavigator />
</NavigationContainer>
)
}
const Stack = createStackNavigator()
function RootNavigator() {
return (
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Root" component={BottomTabNavigator} />
...
</Stack.Navigator>
)
}
BottomTabNavigator
import React from "react"
import { Linking, TouchableWithoutFeedback, View } from "react-native"
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs"
import { createStackNavigator } from "#react-navigation/stack"
import { Feather } from "#expo/vector-icons"
import Profile from "src/screens/profile"
import SignIn from "src/screens/sign-in"
const BottomTab = createBottomTabNavigator()
export default function BottomTabNavigator() {
const TabIcon = ({ name, color }) => <Feather name={name} color={color} size={20} />
return (
<BottomTab.Navigator
tabBarOptions={{
activeTintColor: Colors.defaultWhite,
style,
}}
>
<BottomTab.Screen
name="Profile"
component={ProfileNavigator}
options={{
tabBarIcon: ({ color }) => <TabIcon name="user" color={color} />,
title: I18n.t("components.tab_navigator.profile"),
}}
/>
)
}
const ProfileStack = createStackNavigator()
function ProfileNavigator() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={Profile} options={{ headerShown: false }} />
<ProfileStack.Screen name="SignIn" component={SignIn} options={{ headerShown: false }} />
</ProfileStack.Navigator>
)
}

How to Navigate from DRAWER NAVIGATION to BOTTOM TAB BAR NAVIGATION in react native?

this url: https://streamable.com/no6anz, is a video showcasing my app's navigation, I want the ability to navigate from a Drawer screen to a SPECIFIC Tab Screen in my Tab Navigation.
For example: If i pressed let's say the 'Messages' drawer item, i would like to navigate to the My Account tab screen in the tab navigator.
So far my implementation has not been the best:
import React, {Fragment, Component} from 'react';
import {View, StyleSheet} from 'react-native';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {createStackNavigator} from '#react-navigation/stack';
import Home from '../Views/HomeView';
import Cart from '../Views/CartView';
import MyAccount from '../Views/MyAccountView';
import Sidebar from '../Views/Sidebar';
import HomeIconColor from './CustomSVGIcons/HomeIconColor';
import CartIconColor from './CustomSVGIcons/CartIconColor';
import PersonIconColor from './CustomSVGIcons/PersonIconColor';
import MenuIconColor from './CustomSVGIcons/MenuIconColor';
import Contact from '../Views/screens/Contact';
import Messages from '../Views/screens/Messages';
import {
NavigationContainer,
DrawerActions,
useNavigation,
} from '#react-navigation/native';
import {BottomTabBar} from '#react-navigation/bottom-tabs';
import Login from '../Views/screens/Login';
import {create} from 'react-test-renderer';
import {createSwitchNavigator} from '#react-navigation/compat';
const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
const Switch = createSwitchNavigator();
class Navigator extends Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<NavigationContainer>
<MyDrawerNavigation />
</NavigationContainer>
);
}
}
const MyTabs = (props) => {
const navigation = useNavigation();
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={({route}) => ({
tabBarButton: ['Contact', 'Route2ToExclude'].includes(route.name)
? () => {
return null;
}
: undefined,
})}>
<Tab.Screen
name="Home"
component={Home}
/>
<Tab.Screen
name="MyAccount"
component={MyAccount}
/>
<Tab.Screen
name="Cart"
component={Cart}
/>
<Tab.Screen
name="Sidebar"
component={Sidebar}
/>
<Tab.Screen name="Contact" component={Contact} />
</Tab.Navigator>
);
};
const MyDrawerNavigation = () => {
return (
<Drawer.Navigator drawerPosition={'right'}>
<Drawer.Screen
name="Home"
component={MyTabs}
initialParams={{screen: 'Home'}}
/>
<Drawer.Screen
name="My Account"
component={MyTabs}
initialParams={{screen: 'MyAccount'}}
/>
</Drawer.Navigator>
);
};
const styles = StyleSheet.create({
tabNav: {
backgroundColor: '#000000',
},
});
export default Navigator;
You can pass the screen as the initial param and it would redirect to the correct tab.
<Drawer.Screen name="MyTabs" component={'Tab Component Name'} initialParams={{screen:'MyAccount'}}/>
SOLVED!:
After extensively further researching; I have created my own custom Drawer, with the onPress handler.
The onPress handler initiates the action for navigation to the specified screens.
NOTE: you will have to pass in the navigation ref to the top-level navigation container. You will also have to pass this same reference into your custom drawer module (or any module in that concern)
here's my custom drawer component:
import React, {Component} from 'react';
import {Text, View, Button, StyleSheet} from 'react-native';
import {useNavigation, CommonActions} from '#react-navigation/native';
import * as rootNavigator from '../components/rootNavigator';
const CustomDrawer = () => {
return (
<View style={styles.container}>
<Button
title="My Account"
onPress={() => rootNavigator.navigate('MyAccount')}
/>
<Button
title="Contact"
onPress={() => rootNavigator.navigate('Contact')}
/>
<Button title="Cart" onPress={() => rootNavigator.navigate('Cart')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 30,
},
});
export default CustomDrawer;
here's the code where I return the DrawerNavBar:
const MyDrawerNavigation = () => {
return (
<NavigationContainer ref={navigationRef}>
<Drawer.Navigator
drawerPosition={'right'}
drawerContent={(props) => <CustomDrawer {...props} />}>
<Drawer.Screen name="Tabs" component={MyTabs} />
<Drawer.Screen name="Contact" component={Contact} />
</Drawer.Navigator>
</NavigationContainer>
);
};

Resources