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

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",
},
});

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

Balise <View> on react-native

i try to make an app on react-native for the first time and I have a problem.
I code a component who show a screen with some text and a button but they didn't shown on the app and I don't know why.
I code on snack.expo.dev, i'm new on this but i try to learn a lot about that informatic language.
import * as React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { StartScreen } from "./routes/Start_page";
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
/*const StartScreen = () => {
return(
<View>
<Text>(Screen 1)</Text>
<Text>Welcome to My App</Text>
<Button
title="Start!"
onPress={() => {}}
>
</Button>
</View>
);
}*/
const DashboardScreen = () => {
return(
<View>
<Text>(Screen 2)</Text>
<Text>Dashboard</Text>
<Button
title="Back"
onPress={() => {}}
>
</Button>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName={"Start"}>
<Stack.Screen name="Start" component={StartScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Dashboard" component={DashboardScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
/*const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});*/
import * as React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
const StartScreen = () => {
return(
<View>
<Text>(Screen 1)</Text>
<Text>Welcome to My App</Text>
<Button
title="Start!"
onPress={() => {}}
>
</Button>
</View>
);
}
I try to add more text to post xD
You just forgot to export the const StartScreen in the file ./routes/Start_page/index.tsx. It will be like this:
import * as React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
export const StartScreen = () => {
return(
<View>
<Text>(Screen 1)</Text>
<Text>Welcome to My App</Text>
<Button
title="Start!"
onPress={() => {}}
>
</Button>
</View>
);
}

React Native - Show native header back icon

is there a way how to show native back icon (different for android nad iOS) in custom header? I have created custom header, but have no idea how to show them.
I'm using react-navigation version 6
My stack:
<Stack.Navigator screenOptions={
stackOptions({
header: (props: any) => <Header {...props}/>,
headerRight: () => HeaderActionIcon({
icon: <SvgSettings/>,
action: () => navigation.navigate('Settings')
})
})}>
My header component:
const Header = ({ ...props }: any) => {
const { options, navigation } = props
return (
<View style={styles.container}>
<Image
resizeMode='repeat'
source={require('../../assets/img/pattern.png')}
style={styles.image}
/>
<View style={styles.wrapper}>
{/* Back press icon */}
<View style={styles.leftItem}>
{/* Back icon should be here.. */}
</View>
{/* Stack title */}
<View style={styles.textWrapper}>
<Text style={[options.headerTitleStyle, styles.titleText]} numberOfLines={1}>
{ options.title }
</Text>
</View>
{/* Settings icon */}
<View style={styles.rightItem}>
{ options.headerRight() }
</View>
</View>
</View>
)}
Thanks for every answer
Here is a sample.
import * as React from 'react';
import { View, Text, Platform } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
function HomeScreen({ navigation }) {
React.useLayoutEffect(() => {
navigation.setOptions({
headerTitle: () =>
Platform.select({
android: <Text>{'Left android'}</Text>,
ios: <Text>{'Left ios'}</Text>,
}),
headerRight: () =>
Platform.select({
android: <Text>{'Right android'}</Text>,
ios: <Text>{'Right ios'}</Text>,
}),
});
}, []);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
import * as React from 'react';
import { View, Text, Platform } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
function HomeScreen({ navigation }) {
React.useLayoutEffect(() => {
navigation.setOptions({
headerTitle: () =>
Platform.select({
android: <Text>{'Left android'}</Text>,
ios: <Text>{'Left ios'}</Text>,
}),
headerRight: () =>
Platform.select({
android: <Text>{'Right android'}</Text>,
ios: <Text>{'Right ios'}</Text>,
}),
});
}, []);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;

React Native - Update text after clicking button

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

TypeError: undefined is not an object (evaluating props.navigation.navigate)

I have an icon on the right side of my Header. When pressed I want to be transferred to another page. However, it comes up with an error.
This is my 'icon' screen:
import React, { Component } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
const Login = props => {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => {
props.navigation.navigate({routeName: 'Login'});}}>
<Image
source={{
uri:
'https://clipartart.com/images/login-icon-clipart-5.jpg',
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
}
export default Login;
This is my 'navigation' screen:
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import React from 'react';
import Homepage from './screens/Homepage';
import Checkoutpage from './screens/Checkoutpage';
import Filterpage from './screens/Filterpage';
import Locationpage from './screens/Locationpage';
import Menupage from './screens/MenuPage';
import Welcomepage from './screens/Welcomepage';
import Loginpage from './screens/Loginpage';
import Finalpage from './screens/Finalpage';
import Login from './Components/Login';
const Navigation = createStackNavigator({
Home:Homepage,
Checkout: Checkoutpage,
Filter: Filterpage,
Location: Locationpage,
Menu: Menupage,
Welcome: Welcomepage,
Login: Loginpage,
Final: Finalpage
},
{
defaultNavigationOptions: {
headerRight:() => <Login/>
}
}
);
I'm very new to react-native. So if you found the problem, can you please explain thoroughly so I understand. Thank you!!
So it looks like you are expecting the navigation object to be part of the props passed to your <Login/> component. This object is only defined for screen components in react-navigate.
This means that you need to get access to the navigation functionality some other way. Luckily, this library provides you with the useNavigation() hook. So using that in your component would look something like:
// react-navigation v5+
import { useNavigation } from '#react-navigation/native';
const Login = () => {
const navigation = useNavigation();
return (
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
onPress={() => {
navigation.navigate({ routeName: "Login" });
}}
>
<Image
source={{
uri: "https://clipartart.com/images/login-icon-clipart-5.jpg",
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
};
It seems to me you are using React Navigation v4.x , in order to use the useNavigation hook you need to upgrade to v5.x.
The navigation prop will be passed to all screens by default and you can use the useNavigation hook like #faelks suggested (if needed in other components).
UPGRADE TO v5 FIRST.
Here you have a little example for v5.x version:
import React from 'react'
import { Button, View, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
const Home = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go to login" onPress={() => navigation.navigate('Login')} />
</View>
)
const Login = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
const Main = createStackNavigator()
const mainConfig = {
// configuration for this stack
initialRouteName: "Home",
}
export default props => (
<NavigationContainer>
<Main.Navigator {...mainConfig}>
<Main.Screen name="Home" component={Home} />
<Main.Screen name="Login" component={Login} />
{/* Other screens for this stack */}
</Main.Navigator>
</NavigationContainer>
)
const styles = StyleSheet.create({
component: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})