React Native - Update text after clicking button - react-native

I want to update the text after clicking button.
But couldn't find a way to do this.
The code is like:
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer, CommonActions } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen({ navigation }) {
const state = {
user: 'test',
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{state.user}'s profile</Text>
<Button
title="Change user param"
onPress={() =>
navigation.dispatch({
...CommonActions.setParams({ user: 'Wojtek' }),
})
}
/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Expo example
I've tried navigation.setParams() and this.setState(), they couldn't work with the code I attached above.

You have to use hooks in functional components. So the code would be something like this:
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer, CommonActions } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen({ navigation }) {
const [user, setUser] = React.useState('test');
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>{user}'s profile</Text>
<Button
title="Change user param"
onPress={() => setUser("keidakira") }
/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Check it's working at Expo Link

Related

Correct way of presenting a new screen with a stack?

I have a signup page with 4 steps (4 separate screens). On the first page, the user enters their username in a field, on the second page a display name, on the third their birthday, and on the fourth their password.
Here's my current signup screen file:
import React from 'react';
import { View, Text, Button } from 'react-native';
const SignupScreen = () => {
return (
<View>
<Text>First step</Text>
<Button
title="Next step"
/>
</View>
);
}
export default SignupScreen;
But I'm a bit confused as to how to present the next screen when the user taps the Button. How do I create a Stack here? Or would I do it in the App.js file?
Here is my App.js:
import { StatusBar } from 'expo-status-bar';
import { FlatList, StyleSheet, Text, View, TouchableHighlight } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import {
RootStack,
TabsStack,
SignupStack
} from './navigation/navigation';
export default function App() {
return (
<NavigationContainer>
<RootStack.Navigator>
<RootStack.Screen
name="Tabs"
options={{ headerShown: false }}
component={TabsStack}
/>
<RootStack.Screen
name="SignupStack"
options={{ headerShown: false }}
component={SignupStack}
/>
</RootStack.Navigator>
</NavigationContainer>
);
}
And here is my navigation.js file:
import React from 'react';
import { FlatList, StyleSheet, Text, View, TouchableHighlight } from 'react-native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import SignupScreen from '../screens/SignupScreen';
export const RootStack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const SignupNav = createNativeStackNavigator();
export const TabsStack = () => (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="History" component={SecondScreen} />
<Tab.Screen name="Third" component={ThirdScreen} />
<Tab.Screen name="Fourth" component={FourthScreen} />
</Tab.Navigator>
);
export const SignupStack = () => (
<SignupNav.Navigator>
<SignupNav.Screen
name="Signup"
component={SignupScreen}
options={{ headerTitle: 'Sign up' }}
/>
</SignupNav.Navigator>
);
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home</Text>
</View>
);
}
function SecondScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Second</Text>
</View>
);
}
function ThirdScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Third</Text>
</View>
);
}
function FourthScreen({ navigation }) {
function onPressButton() {
navigation.navigate('SignupStack');
}
return (
<View>
<FlatList
data={[
{key: 'Signup'},
]}
renderItem={({item}) => <TouchableHighlight onPress={onPressButton} underlayColor="white"><Text>{item.key}</Text></TouchableHighlight>}
/>
</View>
);
}
What's the correct way of doing this?
Thank you
the best way that i know, make all the screen as component and import it in the signup screen
signup.js
/*
import all you component(pages) here...
*/
const [screen, setScreen] = useState(1)
{screen == 1 ? (
<ScreenOne
onNext={()=>setScreen(2)}
/>
) : screen == 2 ? (
<ScreenTwo
onNext={()=>setScreen(3)}
/>
) : screen == 3 ? (
<ScreenThree
onNext={()=>setScreen(4)}
/>
)
}
You can pass all your state and callback function from signup page to all the component get value from the component

React Native — React-Navigation back button on wrong side of appbar?

Okay so I'm just jumping into React Native and I'm going through the docs with the react-navigation package. Whenever a screen is pushed onto the stack, the animation goes from right-left by default—Also I'm noticing the back button is on the right side of the appbar instead of the left be default. Is this by design or have I set something up incorrectly?
Also ignore the FC I'm using, I know it's not recommended but I'm just getting a feel for RN 😅
See image and code below:
import { StatusBar } from "expo-status-bar";
import { Button, StyleSheet, Text, View } from "react-native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { BaseNavigationContainer } from "#react-navigation/native";
import { FC } from "react";
import { StackScreenProps } from "./Types";
const Home: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Hello World </Text>
<Button
title="Switch Page"
onPress={() => {
navigation.navigate("About");
}}
/>
</View>
);
};
const About: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Learn the Process First</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
};
const Stack = createNativeStackNavigator();
export default function App() {
return (
<BaseNavigationContainer>
{/* #ts-ignore */}
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="About" component={About} />
</Stack.Navigator>
</BaseNavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

Unable to navigate to new screen react native getting an error undefined Object navigate.navigation

Unable to navigate to new screen react native getting an error:
TypeError: undefined is not an object (evaluating 'navigation.navigate')
Can someone explain where I go wrong?
Below is the code I'm using.
const MessagesScreen = ({navigation}) => {
return (
<Container>
<FlatList
data={Messages}
keyExtractor={item=>item.id}
renderItem={({item}) => (
<Card onPress={() => navigation.navigate('Chat', {userName: item.userName})}>
<UserInfo>
<UserImgWrapper>
<UserImg source={item.userImg} />
</UserImgWrapper>
<TextSection>
<UserInfoText>
<UserName>{item.userName}</UserName>
<PostTime>{item.messageTime}</PostTime>
</UserInfoText>
<MessageText>{item.messageText}</MessageText>
</TextSection>
</UserInfo>
</Card>
)}
/>
</Container>
);
};
export default MessagesScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
});
it's seem that you forget to declare your screen in Navigator stack. something like this
<Stack.Screen
name="MessagesScreen"
component={MessagesScreen} />
this is an example from official page with
react navigation v5
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;

Go from child navigation to parent navigation

I have two NavigationContainer. What I want is when I am on the SignIn screen go to the MainPage. And the problem goes when I am in MainPage > Profile. The Button Logout does not go to the SignIn Screen.
App.js
import React from "react";
import {SignIn} from './src/screen/authentication/signIn'
import {SignUp} from "./src/screen/authentication/signUp";
import {MainPage} from "./src/screen/drawer";
import {createStackNavigator} from "#react-navigation/stack";
import {NavigationContainer} from "#react-navigation/native";
const Stack = createStackNavigator();
class App extends React.Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="SignIn" headerMode={null}>
<Stack.Screen name="SignIn" component={SignIn} />
<Stack.Screen name="SignUp" component={SignUp} />
<Stack.Screen name="Home" component={MainPage} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
drawer.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import {Dashboard} from "./dashboard/dashboard";
import {AddWidget} from "./addWidget/addWidget";
import {Profile} from "./profile/profile";
const Drawer = createDrawerNavigator();
export function MainPage({navigation}) {
return(
<NavigationContainer independent={true}>
<Drawer.Navigator>
<Drawer.Screen name="Dashboard" component={Dashboard} />
<Drawer.Screen name="Add widget" component={AddWidget} />
<Drawer.Screen name="Profile" component={Profile} initialParams={{navigation: () => navigation.navigate('SignIn')}} />
</Drawer.Navigator>
</NavigationContainer>
);
}
Profile.js
import * as React from 'react';
import {Button, Text, View} from "react-native";
import {useHistory} from "react-router-dom";
import {styles} from "./styles"
export function Profile({navigation}) {
const history = useHistory();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>Username</Text>
<Button title="Logout" onPress={() => navigation.navigation} />
</View>
);
}
A trick that I found is printing props with console.log and finding the function inside the object.
So what I did is changing the name of initialparams from Profile, navigation to parentNaivgation. And also removing ({navigation}) to (props) in the Profile component.
At the end, the route to finding the function navigation was props.route.params.parentNavigation.navigate("SignIn")
you should be able to just do this:
<Button title="Logout" onPress={() => navigation.navigate("SignIn")} />
if the above doesn't work, you can try this:
import * as React from 'react';
import {Button, Text, View} from "react-native";
import {useHistory} from "react-router-dom";
import { useNavigation } from '#react-navigation/native';
import {styles} from "./styles"
export function Profile() {
const history = useHistory();
const navigation = useNavigation();
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.title}>Username</Text>
<Button title="Logout" onPress={() => navigation.navigate("SignIn")} />
</View>
);
}

How to pass data through stack navigation to a specific screen on react native tabs?

I'm creating a bottom tabs in react native, which will have two screens Home and News.
But first, user will need to Sign In and the users data will be passed from the login screen to Home screen. How do i pass those data. By using
navigation.navigate('Home', {Name: Name});
I can successfuly retrieve the data in Homescreen, if I just use two screen(Login and Home in a stack). However, when I change to navigate to the tabs(which includes Home and News), it doesnt work with error 'Undefined is not an object(evaluating 'route.params.Name'.
May you guys show me which part did I miss?
Here's the app.js code.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import HomeScreen from './homescreen';
import NewsScreen from './newsscreen';
import LoginScreen from './loginscreen';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { createStackNavigator } from '#react-navigation/stack';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
const LoginStack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<LoginStack.Navigator screenOptions={{headerShown: false}}
initialRouteName="Login">
<LoginStack.Screen name="Login"component={LoginScreen}/>
<LoginStack.Screen name="MyTabs" component={MyTabs} />
</LoginStack.Navigator>
</NavigationContainer>
);
}
export default App;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Following is the homescreen code:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function HomeScreen({route, navigation}) {
var Name = route.params.Name;
return (
<View style={styles.container}>
<Text>{Name}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
And finally here's the login code:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
export default function LoginScreen({navigation}) {
const Name = 'Boy';
const login = () => {
navigation.navigate('MyTabs', {Name: 'Boy'});}
return (
<View style={styles.container}>
<Text>LoginScreen</Text>
<TouchableOpacity
onPress={login}
><Text
>LOGIN</Text>
</TouchableOpacity>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})
I'm trying to learn how to pass data from a screen to another screen, in which the screen is located inside a tab stack. I hope you guys can understand the question and provide me with your opinion and solution. Thanks.
Output:
It needed just this little modification in MyTabs component:
function MyTabs({ navigation, route }) {
const { name } = route.params;
console.log(name);
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={() => <HomeScreen name={route.params.name} />}
/>
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
Here is the working solution:
App.js
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import HomeScreen from './home';
import NewsScreen from './newscreen';
import LoginScreen from './login';
// You can import from local files
const Tab = createBottomTabNavigator();
function MyTabs({ navigation, route }) {
const { name } = route.params;
console.log(name);
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={() => <HomeScreen name={route.params.name} />}
/>
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
const LoginStack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<LoginStack.Navigator
screenOptions={{ headerShown: true }}
initialRouteName="Login">
<LoginStack.Screen name="Login" component={LoginScreen} />
<LoginStack.Screen name="MyTabs" component={MyTabs} />
</LoginStack.Navigator>
</NavigationContainer>
);
}
export default App;
LoginScreen
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import React from "react";
export default function LoginScreen({ navigation }) {
const Name = 'Name From Login Screen';
const login = () => {
console.log("hi");
navigation.navigate('MyTabs', { name : Name });
}
return (
<View style={styles.container}>
<View style={styles.bottomView}>
<TouchableOpacity onPress={login} style={styles.button}>
<Text style={styles.textStyle}>LOGIN</Text>
</TouchableOpacity>
</View>
</View>
);
}
Home.js
import { Text, View, StyleSheet } from 'react-native';
import React from "react";
export default function HomeScreen({route, navigation, name}) {
console.log("***",name)
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
</View>
);
}
Working Expo Snack example.
It's a little complicated to explain react native screens once you start combining bottomtabnavigator and stack navigator and even drawernavigation.
you may need to create stack navigation inside tab navigation like this.
//creating a separate stack within your tab
const HomeStack = createStackNavigator()
const HomeStackNavigator = () => {
return (
<HomeStack.Navigator screenOptions={{headerShown: false}}
initialRouteName="HomeScreen">
<HomeStack.Screen name="Home"component={HomeScreen}/>
</HomeStack.Navigator>
)
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator initialRouteName="HomeStackNavigator">
<Tab.Screen name="HomeStackNavigator" component={HomeStackNavigator} />
<Tab.Screen name="News" component={NewsScreen} />
</Tab.Navigator>
);
}
I believe, different navigators doesn't really talk to each other well. If you are using different navigator be prepare to nest stack navigators inside them.
The idea is, the parent of each display component should be a stack navigator. This will also allow you to better control your screenOptions.