How to navigate to another screen from a function component? - react-native

I have a tabBarNavigation and i have a Home component. In the Home component i want to be able to navigate between two different screens. I have a component called ReadButton which when pressed should take me to another screen called 'BookScreen'. Now i have written so my HomeStack component have two screens 'HomeScreen' and 'BookScreen'. My problem is i cant make the 'ReadButton' to navigate to 'BookScreen' when pressed. It says ''Undefined is not an object(evaluating props.navigation.navigate).
...//This is in the main class provided by react
const HomeStack = createStackNavigator(
{
Home: HomeScreen,
Book: BookScreen,
},
config
);
const tabNavigator = createBottomTabNavigator({
HomeStack,
LinksStack,
SettingsStack,
});
tabNavigator.path = '';
export default tabNavigator;
...
//Below is the ReadButton class in a seperate file
import {withNavigation} from 'react-navigation'
const ReadButton = (props) => {
const [ReadPressed, setReadPressed] = useState(true)
const {navigate} = props.navigation.navigate
if(ReadPressed){
return(
<View>
<TouchableOpacity style={styles.buttonstyle} onPress={navigate("Home")}>
<Text style={styles.textstyle}> READ </Text>
</TouchableOpacity>
</View>
)
}
else {
return(
props.book
)
}
}
// Another class where i have my <ReadButton>
function BookCover(){
<TouchableOpacity style={styles.bottomFlexItemWhenClicked} onPress= .
{() => setBookCoverState(true)}>
<Text style={styles.BackgroundText}>{props.text}</Text>
<ReadButton book={props.book} navigation={props.navigation}>
</ReadButton>
</TouchableOpacity>)}
}
export default withNavigation(ReadButton);
Now i have tried putting 'Book: BookScreen' over 'Home: HomeScreen' and then the screen actually shows but i cant navigate between them. What am i missing?

Maybe you can try hooks?
install hooks: yarn add react-navigation-hooks#alpha
and then use it in your function component:
import { useNavigation } from 'react-navigation-hooks'
export default function Screen1 () {
const { navigate } = useNavigation()
return (
<Button
title='Try'
onPress={() => { navigate('Screen2') }}
/>
)
}

Please note that components inside the HomeScreen or BookScreen won't receive the navigation prop.
1.Either you send them manually like this
<ReadButton navigation={this.props.navigation}/>
or
2.Use the built in withNavigation of react-navigation like this
import {withNavigation} from 'react-navigation'
const ReadButton=(props)=>{}//Now you can access navigation prop here
export default withNavigation(ReadButton)
Second method will come to handy when your component is deeply nested and you want to access the navigation prop without manually passing the props.

Related

React Native component onPress navigation Button Native-Base

I am developing an android app with React Native and Native-Base.
In my component button i can't get onpress to work to change page.
import React from "react";
import { StyleSheet, View, TouchableOpacity } from "react-native";
import { NativeBaseProvider, Button, Text } from "native-base";
const ButtonAPP = (props) => {
//const linkBottom = props.linkBottom;
const textBottom = props.textBottom;
return (
<NativeBaseProvider>
<View style={styles.viewButtonAPP}>
<Button
shadow={2}
style={styles.buttonAPP}
onPress={() => props.navigation.navigate("Home")}
>
<Text style={styles.textButton}>{textBottom}</Text>
</Button>
</View>
</NativeBaseProvider>
);
};
const styles = StyleSheet.create({
styles....
});
export default ButtonAPP;
THe error is:
navigate is not defined
I don't understand why for pages in my app it works but for a component like the button it doesn't
The navigation object will be passed as props by the navigation framework only to components that are defined as screens inside a navigator. If this is not the case, then the navigation object will not be passed to this component.
You have three choices.
1) Use the useNavigation hook
const ButtonAPP = (props) => {
const navigation = useNavigation();
...
<Button
shadow={2}
style={styles.buttonAPP}
onPress={() => navigation.navigate("Home")}
>
}
2) Pass the navigation object as a prop from a parent that is a screen defined in a navigator
Assume that ScreenA is a screen that is defined in a navigator, e.g. a Stack. This would look like the following snippet.
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="ScreenA" component={ScreenA} />
</Stack.Navigator>
);
}
Assume that ButtonApp is used as a child in ScreenA. Then, we can pass the prop manually, since the framework will not do this.
const ScreenA = (props) => {
return <ButtonApp navigation={props.navigation} />
}
const ButtonAPP = (props) => {
...
<Button
shadow={2}
style={styles.buttonAPP}
onPress={() => props.navigation.navigate("Home")}
>
}
3) Let ButtonApp be a screen inside a navigator
This choice usually does only make sense for actual views in the application and not for individual components. However, this is still an option.
Using the same example as in 2). However, this will work with any navigator.
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="ButtonApp" component={ButtonAPP} />
</Stack.Navigator>
);
}
Accessing the navigation object via props as you have tried initially works in this case as well.

React-Navigation: Navigation onPress doesn't work

I am a bit confused about this navigation system. I have root which I contain navigations in it. And I have two different screens. No problem till here. I put initialRoute and displaying SignInScreen. Also put a button for Sign Up screen but that button isn't working.
Root.js
const ScreenNavigator = createStackNavigator({
SignIn: SignInScreen,
SignUp: SignUpScreen,
},
{initialRouteName: 'SignIn' }
);
const ScreenContainer = createAppContainer(ScreenNavigator);
export default class Root extends Component{
render(){
return(
<ScreenContainer style={styles.container} />
);
}
}
and SignInScreen:
import SignUpScreen from '../screens/Signup';
export default class SignInScreen extends Component{
constructor(props){
super(props);
}
render(){
return(
<View style={styles.container}>
<Text>Sign in Screen </Text>
<Button
title={'Sign up'}
onPress={() => this.props.navigation.navigate('SignUpScreen')}
/>
</View>
);
}
}
is it something that I am missing here? Thank you for help.
There is nothing wrong in the code, you just miss spell the route.
There is no route name SignUpScreen, correct route name is SignUp and SignIn
confusion is due to change in api of react navigation
before we define a route like
Login: {
screen: LoginScreen
}
so login is a route name and screen is just a component we need to render
but after 2^ version, it changed to
{SignIn: SignInScreen}
so now name is SignIn and component is SignInScreen
even if you want a route name as component just do
const ScreenNavigator = createStackNavigator({
SignInScreen,
SignUpScreen,
},
now you route name is SignInScreen and SignUpScreen
hope this information is enough
Issue in route name.
onPress = {() => this.props.navigation.navigate('SignUp')}
Try to keep the route names in constant file. It may make things easier to handle.
const routes = {
route1: 'route1',
route2: 'route2',
};
const ScreenNavigator = createStackNavigator({
[routes.route1]: Screen1,
[routes.route2]: Screen2,
},
{initialRouteName: routes.route1 }
);

React-Navigation this.props.navigation.navigate undefined is not an object

I am using react-navigation but my codes return ; this undefined is not an object (evaluating '_this2.props.navigation.navigate)
how can i fix this error?
myCodes;
import React, { Component } from 'react';
import Login from './components/LoginScreen/LoginScreen';
import AddNewUser from './components/AddNewUserScreen/AddNewUserScreen';
import { createStackNavigator } from 'react-navigation';
class App extends Component{
render(){
return(
<Login />
);
}
}
const RootStack = ({ createStackNavigator }) => (
{
Login: Login,
AddNew: AddNewUser,
});
export default App;
LoginScreen.js
<TouchableOpacity style={styles.ButtonContainer} onPress={()=> this.props.navigation.navigate('AddNew')}>
<Text style={styles.buttonText} >GİRİŞ</Text>
</TouchableOpacity>
You should start your app by calling RootStack like this:
class App extends Component{
render(){
return(
<RootStack />
);
}
}
also you can set initialRout in stack like this:
const RootStack = createStackNavigator({
Login: Login,
AddNew: AddNewUser,
}, { initialRouteName: 'Login'} )
Now, as you define, your app will start with login page and it has this.props.navigation by itself so you can use this.props.navigation.navigate('AddNew') without error.
But if you need to use navigation from a component, you have to send this.props.navigation from parent to component like this:
<YourComponent navigation={this.props.navigation}/>
Then you can use navigation in YourComponent component.
I hope this can help you

React Navigation StackNavigator not appearing when used inside another view

I'm attempting to use a React Navigation StackNavigator for a process that includes a static component at the top of the page and varying components at the bottom. The code I'm using is:
const Navigator = StackNavigator ({
splash: Splash,
prompt: Prompt,
pinCheck: PinCheck
}, {
initialRouteName: 'splash'
});
export default class Login extends React.Component
{
constructor (props)
{
super (props);
// code to set up animation state
}
componentDidMount()
{
// code to set up animation
}
finish_ (state)
{
this.props.navigation.navigate ('main', state);
}
render()
{
const screen = Dimensions.get('screen');
return (
<KeyboardAvoidingView style={Global.styles.verticalFill} ref={this.saveContainerRef}>
<ScrollView style={{flex: 1}} contentContainerStyle={{justifyContent: 'space-between'}}>
<Animated.View style={{opacity:this.state.fade1,alignItems:'center'}} >
<Image
style={{width:screen.width * 0.6,height: screen.height*0.55}}
source={imgLogo}
resizeMode='contain'
/>
<Navigator />
</Animated.View>
</ScrollView>
</KeyboardAvoidingView>
);
}
}
When I run this, however, my initial route component is not shown. It works correctly if I swap <Navigator/> to <Splash/> however, so the component itself definitely works in this context.
Any ideas what's wrong?
There is a problem in your navigation setup.
All the routes in the StackNavigator must declare a screen
as mentioned in the docs
const Navigator = StackNavigator ({
splash: {
screen: splash
},
prompt: {
screen: prompt
},
pinCheck: {
screen: pinCheck
}
}, {
initialRouteName: 'splash'
})

StackNavigator through Component gives undefined error

I was trying to use StackNavigator for navigation and it works when I use it to go from one screen to the other as explained here. But when I try to have a subcomponent to navigate through itself, the navigation doesn't seem to work and I couldn't find any solution to it.
As given in the code below, I'm trying to use the Test Component in which there is a button that can be clicked to move from HomeScreen to ChatScreen.
I'm pretty sure the solution is something basic, but I really can't find it anywhere.
Here's my code:
import React from 'react';
import {
AppRegistry,
Text,
View,
Button
} from 'react-native';
import { StackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
let userName = 'Ketan';
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat', { user: userName })}
title={"Chat with " + userName}
/>
<Test />
</View>
);
}
}
class ChatScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: `Chat with ${navigation.state.params.user}`,
});
render() {
const { params } = this.props.navigation.state;
return (
<View>
<Text>Chat with {params.user}</Text>
</View>
);
}
}
class Test extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Button
onPress={() => navigate('Chat', { user: 'TestBot' })}
title={'This is a test'}
/>
</View>
)
}
}
const NavApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
AppRegistry.registerComponent('NavApp', () => NavApp);
Here's the error I'm getting:
Here's the demo to test: https://snack.expo.io/HyaT8qYob
I hope my question is clear enough of what I mean.
Since your Test component does not belong to navigation stack it doesn't have the navigation prop. You can do couple of things.
Simple one is to pass the navigation to the child component like the example below.
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat', { user: userName })}
title={"Chat with " + userName}
/>
<Test navigation={this.props.navigation} />
</View>
);
The second option is, you can use withNavigation from react-navigation. You can find more details about it here
import { Button } 'react-native';
import { withNavigation } from 'react-navigation';
const MyComponent = ({ to, navigation }) => (
<Button title={`navigate to ${to}`} onPress={() => navigation.navigate(to)} />
);
const MyComponentWithNavigation = withNavigation(MyComponent)
withNavigation
withNavigation is a higher order component which passes the
navigation prop into a wrapped component. It's useful when you
cannot pass the navigation prop into the component directly, or
don't want to pass it in case of a deeply nested child.