React Native Stack Navigation With Class Component [duplicate] - reactjs

This question already has answers here:
What is the best way to redirect a page using React Router? [closed]
(5 answers)
Closed 1 year ago.
I am currently building a react native app and am using a stack navigator to navigate between the screens in my app. In my App.js, I am currently storing the screens in this format:
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="screen1">
<Stack.Screen name="screen1" component={Screen1}></Stack.Screen>
<Stack.Screen name="screen2" component={Screen2}></Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
);
}
After the user is in screen 1, I want to be able to navigate to screen 2 on the press of a button. I read through the documentation and I only saw examples on how to do this with functional components, for example:
function Screen1({ navigation }) {
return (
<View>
<Button title="Go to Home" onPress={() => navigation.navigate('screen2')} />
</View>
);
}
But how can I do this with a class component:
class Screen1 extends Component {
render() {
return(
<View>
// This does not work because I do not know how to pass in the navigation object
<Button title="Go to Home" onPress={() => navigation.navigate('screen2')} />
</View>
)
}
}
Where do I pass in the { navigation } ?

You dont have to pass navigation, its passed as a prop.
You can access it like below
this.props.navigation.navigate('nextScreen')

1 : import { Link, withRouter } from 'react-router-dom';
2 : export default withRouter(Component);
Login = () => {
this.props.history.push("/login")
}

Related

react native : what is principle of stack navigation?

tired but i want to implement react native stack navigation.
import React, { useState } from "react";
const StackScreen = () => {
let InitialRoute;
let First;
let Second;
let Third;//assume they are screens of my app.
const [stack, setStack] = useState([InitialRoute]);
const replace = (screenName: any) => {
const tmp: Array<any> = stack.filter((el: any) => el = !screenName);
setStack([...stack, screenName]);
}
const navigate = (screenName: any) => {
stack.indexOf(screenName) == -1 ? setStack([...stack, screenName]) : replace(screenName);
}//navigate to another screen
const goBack = () => {
if (stack.length > 1) {
const tmp = [...stack];
tmp.pop();
setStack(tmp);
}
}//they are fuctions.
return stack[stack.length - 1];
}
const App = () => {
return (
<View>
<Appbar />
<StackScreen />
<BottomTab or anything i dont want to render while change screens./>
</View>
)
}
i make toy example even if it's not accurate with reality.
but i have question.
i enter the FirstScreen to SecondScreen. after a while, i pop the secondScreen.
in this case, my code will re-render the FirstScreen.
is the screen re-rendered in react - navigation?
if ans is no, how to i implement without rendering?
what is problem of my idea?
To Implement stack navigation in react native first add these packages https://reactnavigation.org/docs/getting-started according to your environment (EXPO CLI/React-native CLI) .
Stack Navigation Example
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>press back button to go back</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Stack navigation Basic concept
Stack Navigation Mean first Screen In last out. it mean, that that screen which display first and navigate to other and other screen, by pressing back button that first screen will display in last.
In react-navigation, your component will not automatically be re-rendered. See Refresh previous screen on goBack() for discussion on solutions to this issue in react-navigation.
This question is pretty general and I'm not sure how to answer. Can you give more detail on the feedback you're looking for?

React Navigation routes disappear from history on navigate

I have a screen in my app (CameraScreen) that is both in my Tab Navigator and Stack Navigator shown below (there are some more Tab Screens and Stack Screens that I removed for simplicity):
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Screen
name="Camera"
component={CameraScreen}
/>
</Tab.Navigator>
);
};
const Navigation = () => {
return (
<NavigationContainer theme={Theme}>
<Stack.Navigator headerMode="none">
<Stack.Screen name="Camera" component={TabNavigator} />
<Stack.Screen name="Product" component={ProductScreen} />
<Stack.Screen name="CameraStack" component={CameraScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
Now if I navigate to ProductScreen, then navigate to CameraStack from there and check the navigation state I notice that ProductScreen is nowhere to be found in the routes which I checked using navigation.getState().routes. Thus if I try and use navigation.goBack() it does not go back to the ProductScreen (which would be the expected behaviour).
When I check the routes in ProductScreen, ProductScreen shows up as the last route, however this disappears when I navigate to CameraStack.
I have a hunch that this has to do with the fact that CameraScreen is in both the Tab Navigator and Stack Navigator so for some reason the navigation prop passed to Camera is the Tab Navigator.
For reference my CameraScreen (simplified):
const CameraScreen = ({ navigation, route }) => {
// this doesn't include ProductScreen even if I navigate to CameraStack from the ProductScreen
console.log(navigation.getState().routes);
return (
<View></View>
);
};
and ProductScreen (simplified):
const ProductScreen = ({ navigation }) => {
return (
<View>
<TouchableOpacity
onPress={() => navigation.navigate("CameraStack")}
>
</TouchableOpacity>
</View>
);
};
One idea I can think of to resolve this issue is to manually pass a navigation parameter from ProductScreen but I'm wondering if there is a better way to handle this issue.
I realized this had nothing to do with the fact that I had this screen in both the Tab Navigator and Stack Navigator but was occurring because I was navigating to the same screen using navigation.navigate instead of navigation.push.
The former navigates to the previous location in your stack if you navigate to a screen you've already visited before, but the latter pushes a new route to the navigation state even if it's a screen you've already visited.
Handle backBehavior prop in your Navigator
<Tab.Navigator backBehavior='history'>
<Screen ... />
<Screen ... />
<Tab.Navigator/>
https://reactnavigation.org/docs/bottom-tab-navigator/#backbehavior

How to call drawer navigator inside function in react native

I am new to React-native. So I don't know much about navigation. When I click my image I need to open my drawer side menu.
I called my drawer inside the function.
const Drawer = createDrawerNavigator();
function TopBar(props) {
function sideMenuHandler() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="SideBar" component={SideBar} />
</Drawer.Navigator>
</NavigationContainer>
);
}
return (
<>
<View>
<TouchableWithoutFeedback onPress={sideMenuHandler}>
<Image source={require('../assets/profile.jpg')} onPress{sideMenuHandler}/>
</TouchableWithoutFeedback>
</View>
</View>
</>
);
}
First you have to describe your Drawer at the Root of your application as desribed in the docs.
Answering your question opening, toggling or closing a Drawer pane programmically you can use DrawerActions or the shortcut described below.
Import useNavigation to access navigation props.
import { useNavigation } from '#react-navigation/core';
Apply Actions by dispatching them:
const navigation = useNavigation();
const handlePress = () => {
navigation.toggleDrawer();
}

How to navigate to another screen in a nested navigator in React-Native?

I just implemented bottom navigation bar and it seems like I need to change the way I navigate between screens now on. This is how I was doing it before:
onPress={() => this.props.navigation.navigate('my_profile')}
but now it doesn't work, it shows this message:
Do you have a screen named 'my_profile'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigato
This is how I have implemented the bottom tab:
export default function home_customers() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={home_customer_screen} />
<Tab.Screen name="More" component={settings_screen} />
</Tab.Navigator>
</NavigationContainer>
);
}
//this class below is located in the same file with the function home_customers
class home_customer_screen extends Component{
...
}
//this class is located in a different file that's why I am exporting it
export default class settings_screen extends Component{
render() {
return (
<View>
<TouchableOpacity onPress={() => this.props.navigation.navigate('my_profile')}>
<Text>My profile/Text>
</TouchableOpacity>
</View >
);
}
}
//this is where I am trying to navigate to
export default class my_profile extends Component {
...
}
FYI: I am not using Functions but Classes!
UPDATE
I am using nested navigators. This is the createStackNavigator located in another file:
const AppNavigator = createStackNavigator({
login: {
screen: login
},
home_customers: {
screen: home_customers
},
settings_screen: {
screen: settings_screen
},
my_profile: {
screen: my_profile
},
},
{
initialRouteName: "login"
}
);
From your updated snippet, you seem to be trying to use the react-navigation V4 syntax when defining your stack navigator and the V5 syntax for the tab navigator.
I would suggest you read the stack navigation guide in order to define your screens appropriately.
Once that is done you'll be able to navigate correctly.

React Native Navigation override goBack() of header back button in Stack Navigator

I want to customize the behavior of the default back button in stack navigator locally to one screen.
In the details assuming that on the stack there are screen1|screen2, I want to pass some props from screen2 to screen1 once the button is pressed.
I spent a lot of time reading React navigation docs, searching on internet and coding but I am not able to do this.
FROM DOCS
It's possible that in some circumstances that you want to customize the back button more than you can through the options mentioned above, in which case you can set the headerLeft option to a React Element that will be rendered
I know that the issue concerns the goBack() function of the headerRight component.
I want to override the default function goBack() related to the headerLeft back button with something like navigation.navigate("previousScreen",{{..props}}).
And ( this is very important!! ) I want to use this behavior locally to a specific screen, so not globally.
I have tried with something like this but doesn't works.
export default function App(){
return(
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="FirstScreen" component={FirstScreen}/>
<Stack.Screen name="SecondScreen" component={SecondScreen} options={{headerLeft: () => (
<HeaderBackButton
onPress={() =>navigation.navigate("FirstScreen",{//stuff//})}
title="Info"
color="#fff"
/>
),}}/>
</Stack.Navigator>
</NavigationContainer>
)}
If you are using react navigation v5, you can set the behaviour for a specific screen using :
import { HeaderBackButton } from '#react-navigation/stack';
...
options={{
headerLeft: (props) => (
<HeaderBackButton
{...props}
onPress={() => {
navigation.navigate('screenName');
}}
/>
),
}}
...
You can also set as stack level using screenOptions={{}} instead.
"navigation" and "route" are also available on screen props.
options={({ navigation, route }) => ({headerLeft: ...})
For react-navigation v6, you can use setOptions inside a useEffect
import { HeaderBackButton } from '#react-navigation/elements';
...
const MyScreen = ({navigation}) => {
useEffect( () => {
navigation.setOptions({ headerShown: true,
headerLeft: (props) => (
<HeaderBackButton
{...props}
onPress={() => {
navigation.navigate('MyOtherScreen');
}}
/>
)
});
} );
}
When the component is mounted, register back button press listener
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
}
Then in the function, you can check and handle the action, ex:
onBackButtonPressAndroid = () => {
// Check if the current screen is focused or a subscreen is perhaps
if (this.props.navigation.isFocused()) {
if (someCondition) {
// Do a navigation to a custom screen, pass props here if needed
this.props.navigation.navigate('search')
return true
// Return true if you want to tell react navigation you've handled the back press
}
else if (this.state.offsetTop > 10) {
// Ex. for scrolling to top
this.scrollToTop()
this.setState({
offsetTop: 0,
})
return true
}
}
// Return false if you want to tell react navigation you didn't handle the back press
return false
}
Try passing navigationOptions to a specific screen :
export default function App(){
return(
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="FirstScreen" component={FirstScreen}/>
<Stack.Screen name="SecondScreen" component={SecondScreen}
navigationOptions: ({ navigation }) => ({ headerLeft: (<HeaderBackButton onPress={() => {}}/>)
})}}/>
</Stack.Navigator>
</NavigationContainer>
)}
Either you can specify it there on the navigation.
Or on the Second screen, try this :
class SecondScreen extends React.Component {
static navigationOptions = {
headerLeft: (
<Button
onPress={() => alert('This is a back button!')}
title="Title"
color="#fff"
/>
),
};
}

Resources