I have a component that locks the screen to landscape before rendering.
When I click on the next button, I go to the next screen which unlocks the orientation.
When I click on the previous button, I go back to the first screen.
(The navigation is done by this.props.navigation.navigate('ScreenName') from react-native-navigation).
The screen now gets locked in the componentDidMount method, is there a similar method that gets called when you go back to an already rendered component?
One way you can do this in react-native-navigation is to pass parameters backwards. When you navigate back to your component pass a parameter that indicates that it went back. After that in your file where you want to have the function, have it listening for the wentBack prop.
Navigating backwards with a parameter:
this.props.navigation.navigate('ScreenName', {
wentBack: true,
});
Listening for the parameter:
const { navigation } = this.props,
wentBack = navigation.getParam('wentBack', 'whatever default value - should be false');
Then in your render method you can render conditionally for whatever you want to show:
render() {
return (
<View>
{wentBack ? 'do something it went back!' : 'it didn't go back'}
</View>
);
}
Related
When navigating between screens using the StackNavigator with a fade transition, a user is able to click during the transition animation and possibly hit a TouchableOpacity on the screen that is being navigated away from. The TouchableOpacity registers the hit and thus the app responds accordingly. This is causing issues for "fast clicking" users where they click a button to navigate to a new screen and immediately click where they think a new button will be, but in reality is clicking a button on the previous screen.
Is there a way to prevent any user interaction during these transition animations? I have tried setting the transition duration to 0 like so:
transitionConfig: () => ({
transitionSpec: {
duration: 0
}
})
but the issue still occurs.
I do not want to disable the animation completely, because it is quick enough for most users and they like the animation.
So in your case you can do several things
You can use React Native Activity Indicator -> View
You can use Overlay Library -> react-native-loading-spinner-overlay -> View GitHub
If you like to make loading like facebook / instagram -> then use react-native-easy-content-loader -> View GitHub
you need to flag screen before navigating away; disabling all touchs.
an easy way would be to have a reusable hook that return a transparent absolute positioned View that cover entier page and a callback to enable it;
so you flow will be; enable this which will overlap whole screen and capture any clicks basically disabling them;
something more like:
function useOverlay(){
const [isVisible, toggle] = React.useState(false);
const Component = React.memo(()=><View style={styles.transparentAbsolute} />,[])
return [toggle, isVisible ? Component : null];
}
then inside your Screen before you call navigate just call toggle
and include Component at top of you screen;
export default function TabOneScreen({ navigation }: RootTabScreenProps<'TabOne'>) {
const [ toggle, component ] = useOverlay();
return (
<View style={styles.container}>
{component}
<Button onPress={()=>{toggle(true); navigation.navigate('Home');} title="go home" />
</View>
);
}
I am developing a react-native project. Here is my main screen which can receive route parameters from child screen.
(User can navigate from MainScreen to ChildScreen and vise versa.)
const MainScreen = ({route, navigation}) => {
if (route?.params) {
//do something
} else {
//do something else
}
...
}
When navigating back from child screen to main screen, inside ChildScreen, I have:
//this is inside Child screen
onPress={() =>
navigation.navigate("MainScreen", {data: 'foo'})
}
Above code snippet is a illustration of how I pass route parameter from child screen to main screen.
Overall, it works well. However there is one issue. That's inside the MainScreen, once navigating back from ChildScreen to MainScreen, the value of the parameter inside route?.params is preserved. I mean if I kill the app's process and launch the app again which shows MainScreen again, the
if (route?.params) {
//do something
}
is executed because the route?.params contains the previously passed parameters from child screen. That is bad since I expect a clean start for my main screen. How to get rid of this issue?
Try navigation.push instead of navigation.navigate.
I did some changes in my second screen and comeback to my first screen the data is not updated. After reloading app the data is updated. How to update the data from second screen to first screen navigation without refresh or reload
What i believe without any code is that if you do navigation.goBack() or navigation.navigate() it doesnt call the api if its in your componentDidMount, what you can try is adding an eventlistener called onFocus so that whenever screen is focused you call that :
like this in your componentDidMount
componentDidMount(){
this.focusListener = this.props.navigation.addListener('didFocus', () => {
// The screen is focused
// Calling action to reset current day index to 1
this.getItineryData();
});
}
Hope it helps
I'm developing a react-native / redux app with a bottom-tab-navigator similar to the example at https://reactnavigation.org/docs/en/tab-based-navigation.html#customizing-the-appearance. My screens all connect to a Redux store and display shared data, however I'd like at least one of these screens to ignore the current data in the store and instead re-initialize this data each time it's navigated to (instead of continuing to display the data in whatever state it was last left in).
The screen has a method to do this, but I can't figure out how to call it after the first time the screen is rendered (e.g. from the constructor or componentDidMount() method). I can't call it from the render() method as this causes a "Cannot update during an existing state transition" error.
I need my navigator to somehow cause my HomeScreen.initializeData() method to be invoked each time the Home icon is pressed, but how do I do this?
HomeScreen.js:
initializeData() {
this.props.resetData(initialValue);
}
const initialValue = ...
(resetData() is a dispatch function that re-initializes the Redux store).
Updating state from render() would create an infinite loop. Also, you don’t want to run your state update every time the component re-render, only when the tab button is pressed. This tells me that the proper place to make your state update is some onPress function on the tab button.
So the question now relies on how to implement some onPress function on a tab button. I believe this answer this question:
Is there an onPress for TabNavigator tab in react-navigation?
So I found an answer, it's a little more complicated than might be expected: As Vinicius has pointed out I need to use the tabBarOnPress navigation option, but I also need to make my dispatch function available to this navigation option.
To do this I found I need to pass a reference to my dispatch function (which is available as a property of my screen) into the navigation option, so I've used navigation params to do this and here's what I've ended up with:
HomeScreen.js:
componentDidMount() {
initializeData(this.props);
this.props.navigation.setParams({ homeProps: this.props });
}
export const initializeData = (homeProps) => {
homeProps.resetData(initialValue);
};
const initialValue = ...
AppNavigator.js:
tabBarOnPress: ({navigation, defaultHandler}) => {
const routeName = navigation.state.routeName;
if (navigation.state.params === undefined) {
// no params available
} else if (routeName === 'Home') {
let homeProps = navigation.getParam('homeProps', null);
initializeData(homeProps);
} else if (routeName === ...
...
}
defaultHandler();
}
Notes:
I'm passing props as a navigation param rather than my dispatch function (which also works) as it's more flexible (e.g. it makes all of my dispatch functions available).
initializeData() is called both during construction of HomeScreen (for the first time the screen is displayed) and from the navigation icon (for subsequent displays of the screen).
It's necessary to check that params is defined within the navigation option as it'll be undefined the first time the screen is displayed (as screen construction has yet to occur). This also makes it necessary to call initializeData() during screen construction.
I am passing props and a function to the second page of the navigator as follows:
unlock: function(object) {
switch(true) {
case (object==0): this.setState({a: false});break;
case (object==1): this.setState({b: false});break;
case (object==2): this.setState({c: false});break;
case (object==3): this.setState({d: false});break;
default: this.setState({e: false});break;}
},
Then pass props through the navigator:
this.props.navigator.push({
title: title,
component: component,
passProps: {unlock: this.unlock,a: this.state.a, b: this.state.b,c: this.state.c,d: this.state.d, e: this.state.e}
});
But when I call the function in the second navigator page it updates ok but only to the home page. The information within this second navigator page does not update while I remain on the page. So for example this code:
<Text>{this.props.a}</Text?
Still shows the value prior to activating the function while in the second page. I have to go back to the main page and then return once more to the second page to see the updated value. This only seems to happen with the navigator. With any other method it updates instantly.
The only workaround I had was to both set state within the second page as well as setting props for the home page. It seems a bit of an unnecessary workaround though.
Have you call the unlock function in next component? Until you call it, it will not set the state of that main component, since unlock function is in main component it will only be called on main component , i think that your problem.