Set navigation parameter on goBack in react native - react-native

I have two screens A and B.
When i navigate from Screen A to Screen B I have passed Parameter "onGoBack":false.
On B Screen I have setParameter "onGoBack" as true Which is not working. On go back from Screen B I always receiving "onGoBack" parameter as false only.
Please help to solved this problem.
How can I received updated parameter value on go back.
Below the code I have used to set parameter on Go back from screen B
componentDidMount() {
this.props.navigation.setParams({onGoBack: true});
console.log('Updated Go Back Value: '+this.props.navigation.state.params.onGoBack);
this.backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
this.props.navigation.goBack();
return true;
});
}

You can get the navigation state params whenever a screen is mounted so try this:
import { NavigationEvents } from 'react-navigation';
render() {
return (
<View style={{ flex: 1 }}>
<NavigationEvents
onWillFocus={() => {
// Do your things here
}}
/>
</View>
);
}
Or else,
You can send the params when you're navigating from screen A to screen B:
this.props.navigation.navigate('screenB', { onGoBack: false });
So screen A is already mounted on Stack, so you can use the navigate function to send params. Here, the navigate function will act as goBack(); it won't push a new screen in the stack
this.props.navigation.navigate('screenA', { onGoBack: true });

Related

React-Native navigation jumps to wrong screen with useEffect and setTimeout

I have a navigation stack with different screens that I wan't to render after each other. I set the timeout to be 5 seconds, so it will go to the next screen in the stack.
<Stack.Screen name="StoryScreenOne" component={StoryScreenOne} />
<Stack.Screen name="StoryScreenTwo" component={StoryScreenTwo} />
<Stack.Screen name="StoryScreenThree" component={StoryScreenThree} />
My timeout function is this
useEffect(() => {
setTimeout(() => {
props.navigation.navigate('StoryScreenTwo');
}, 5000);
});
The problem is that if I am at screen two and navigate back to screen one, the next screen that renders is screen three, not screen two as I want it to be.
Any tips for this?
If i understand when you arrive on the screen two there's an other useEffect like this:
useEffect(() => {
setTimeout(() => {
props.navigation.navigate('StoryScreenThree');
}, 5000);
});
I think the setTimeout is still running so if you want to rerender screen 2 on goBack you need to use a clearTimeOut when you press the back button.
Look a this : https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals
But your first screen will not unmount when you go navigate so you need to use a listener to relaunch the UseEffectlike this :
import { useFocusEffect } from '#react-navigation/native';
function Profile() {
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
return <ProfileContent />;
}
more info here : https://reactnavigation.org/docs/navigation-lifecycle/

How to get navigation parameter before re-render the page

I'm using react navigation to navigate between pages. I have 2 pages. Let's call them A and B. I have some cards on page A and has touchable opacities on cards to navigate to page B with an id (using this id for getting data from the server).
On first navigation from A to B everything works well. But when i go back to page A from sidemenu and select another card (i mean send another id as parameter to page B) its show me same page with first navigate. I figured out navigation parameter changes after the render.
i tried that lifecycle;
export class TanksContent extends React.Component {
constructor(props){
super(props);
this.state = {
isLoading:true,
tanks:[],
}
}
componentDidMount(){
this.getData();
}
componentWillUnmount(){
this.setState({
isLoading: true
});
}
componentWillUpdate(){
this.getData();
}
getData(){
//fetching data on here from server and set state for loading and data.
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
// screen
)
Its refreshing the page again and again... So its not working well. How could i stop rendering until parameter has changed? (its possible to user choose the same parameter again)
I solved that problem.
componentDidUpdate(prevProps) {
if(this.props.id!==this.state.id){
this.setState({
id: this.props.id,
isLoading: true
});
this.getData();
}
}
with that function. if someone need help about that just comment and i will do my best for you.

Navigation.goBack() with an API call in React-Native

In my application, I have few cases where navigation.goBack() cannot be used. I use react-navigation for navigation. When i'm in the detail screen, When I go back, I want to send an API call to get the latest records to the parent screen. So I used, navigation.navigate() instead of navigation.goBack(); But, this makes my app slow if I navigate and navigate back few times. It gets very slow if I do this few more times. What is the reason behind this? How the navigation.navigate() differs from navigation.goBack()?
What is the preferred way of handling this kind of scenario?
is there a way to pass param from navigate.goback() and parent can listen to the params and update its state?
You can pass a callback function as parameter (as mentioned in other answers).
Here is a more clear example, when you navigate from A to B and you want B to communicate information back to A you can pass a callback (here onSelect):
ViewA.js
import React from "react";
import { Button, Text, View } from "react-native";
class ViewA extends React.Component {
state = { selected: false };
onSelect = data => {
this.setState(data);
};
onPress = () => {
this.props.navigate("ViewB", { onSelect: this.onSelect });
};
render() {
return (
<View>
<Text>{this.state.selected ? "Selected" : "Not Selected"}</Text>
<Button title="Next" onPress={this.onPress} />
</View>
);
}
}
ViewB.js
import React from "react";
import { Button } from "react-native";
class ViewB extends React.Component {
goBack() {
const { navigation } = this.props;
navigation.goBack();
navigation.state.params.onSelect({ selected: true });
}
render() {
return <Button title="back" onPress={this.goBack} />;
}
}
Hats off for debrice - Refer to https://github.com/react-navigation/react-navigation/issues/288#issuecomment-315684617

How to send data back to previous sceen when using navigation.goBack()?

I've got screen 1 from which I navigate to screen 2 using:
navigation.navigate('Screen2')
From this screen, I would like to go to the previous one, which simple:
navigation.goBack()
However I'm wondering how can I pass some data back to Screen1? Something like wouldn't work navigation.goBack({ myData: 'something' }) so I'm wondering what is the recommended way to do this in general?
You can solve it with 2 ways :
1 : Using navigation method
Pass a method when you are calling that screen through navigation :
this.props.navigation.navigate('Screen2', {
onGoBack: this.refresh,
});
refresh=(data)=> {
}
and when you press back, pass data like
this.props.navigation.state.params.onGoBack('123');
this.props.navigation.goBack();
2 : Using redux store
If you are using redux in your application, just update redux store whenever user presses back button, and get store value in previous screen.
You can pass a callback (onSelect) like this:
SCREEN 1
import React from "react";
import { Button, Text, View } from "react-native";
class Screen1 extends React.Component {
state = { selected: false };
onSelect = data => {
this.setState(data);
};
onPress = () => {
this.props.navigate("Screen2", { onSelect: this.onSelect });
};
render() {
return (
<View>
<Text>{this.state.selected ? "Selected" : "Not Selected"}</Text>
<Button title="Next" onPress={this.onPress} />
</View>
);
}
}
SCREEN 2
import React from "react";
import { Button } from "react-native";
class Screen2 extends React.Component {
goBack() {
const { navigation } = this.props;
navigation.goBack();
navigation.state.params.onSelect({ selected: true });
}
render() {
return <Button title="back" onPress={this.goBack} />;
}
}
Using the navigation method
Pass a method when you are calling that screen through navigation :
this.props.navigation.navigate('Screen2', {
onGoBack: this.refresh,
});
refresh=(data)=> {
console.log(data)
}
and when you press back, pass data like
this.props.route.params.onGoBack('123');
this.props.navigation.goBack();
if you're using v2 or newer, another possibility is using the navigate function, providing key / routeName of the route you're going back to and the params. docs: https://reactnavigation.org/docs/en/navigation-actions.html#navigate
yes goback work for going previous screen to ...and show our data call from api ...goBack()

react-navigation squash navigation stack but preserve rendering?

I'm running in to an issue with react-navigation and a basic StackNavigator where I'd like to navigate back to HomeScreen while preserving the initial render of that component and not "reset" it. It would be compared to multiple goBack() calls until HomeScreen is hit, but in one navigation.
App structure:
- StackNavigator
- HomeScreen
- ChannelScreen
- VideoScreen
There is, however cyclical navigation on ChannelScreen, where you can click another related section and get to another ChannelScreen.
Quickly, the StackNavigator becomes: HomeScreen => ChannelScreen=> ChannelScreen=> ChannelScreen => etc...
We wanted an easy way to get back to HomeScreen, from any ChannelScreen so I employed a basic reset action:
export const resetStackNavigate = (navigation, routeName, params = {}) => {
const resetAction = NavigationActions.reset({
index: 0,
params,
actions: [
NavigationActions.navigate({ routeName })
]
})
navigation.dispatch(resetAction);
}
which works amazingly well with the exception that the reset causes the stack to "reset" so the initial HomeScreen is unmounted and remounted, and all the components/images/etc have to be reloaded.
I've also tried to pass the HomeScreen's state.key (looks like: Init-id-1513113862825-1) down to the ChannelScreen and utilize:
this.props.navigation.goBack(this.props.navigation.state.params.homeScreenKey);
and
this.props.navigation.dispatch(NavigationActions.back({ key: this.props.navigation.state.params.homeScreenKey }));
Both which did nothing.
Is there a way to get back to HomeScreen but preserve the initial screen?
I solved this by caching the first ChannelScreen's this.props.navigation.state.key on navigation to the sub ChannelsScreens:
class SomeComponent extends Component {
_navigateToHome = () => {
const { backKey } = this.props.navigation.state.params;
this.props.navigation.goBack(backKey);
}
_navigateToChannel = () => {
let { backKey } = this.props.navigation.state.params;
if(!backKey) {
backKey = this.props.navigation.state.key
}
navigate('Channel', { backKey });
}
render() {
return (
<View>
{/* the link to another Channel */}
<TouchableOpacity onPress={this._navigateToChannel}>
{/* ... */}
</TouchableOpacity>
{/* Return to HomeScreen */}
<TouchableOpacity onPress={this._navigateToHome}>
{/* ... */}
</TouchableOpacity>
</View>
)
}
}
If you are on the first ChannelScreen, backKey will be null and therefore just .goBack() is called. On each subsequent ChannelScreen the first ChannelScreen's key is passed along allowing .goBack(key) to navigate us back to the HomeScreen.