Screen starting on the bottom - react-native

In react native, I'm using react navigation, and when i'm on the screen "X" and navigate to screen "Y", this is really good, but when i go back to screen "X", that is on the bottom, because when a navigate to screen "Y" i was on the bottom of the screen "X".
What i need: Everytime when i go back to screen "X" this start on the top.
I searched something about this in the docs, however i didnt found nothing about state of screen

You can use useFocusEffect and a ref of your ScrollView to scroll back to the top when the screen comes into focus. Something like:
const scrollRef = useRef<ScrollView>(null);
useFocusEffect(
useCallback(() => {
scrollRef.current?.scrollTo({ x: 0, y: 0, animated: false });
}, [scrollRef])
);
// ...
<ScrollView ref={scrollRef}>

Related

How to prevent user interaction during screen transition animation?

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

How to goBack globally between stacks in React Navigation?

I am using react navigation ("#react-navigation/native": "^5.1.3") and I have the following setup:
BottomNavigation
-stack1
-stack2
It looks like goBack() is local to the stack. What that means is that if I navigate from a page in stack1 to a page in stack2, I am unable to go the the page I came up from.
Solutions (or rather hacks) that didn't work for me:
pass the source screen as param and then navigate. That isn't a real back button and does not play well with android back button.
Put all pages in bottom navigation. Bottom navigation does not have animations it seems, so I can not achieve the right transitions
Put all pages in stack navigation. In this case I lose the fixed bottom navigation. I can add it to each page, but when transitioning it will go away with the old screen and come again with the new one, which is undesirable.
So I am wondering if I am missing something big here, like a globalBack() that I overlooked?!
And also, I am looking for a solution to this problem which remains.
Naturally if you have bottoms tabs with each tab having its own stack navigator, calling navigation.goBack() will go back from one screen inside stack navigator to previous screen inside that same stack navigator. That's how navigation works in pretty much every app. Pressing back button or swiping back does not change tab for you, tabs are more like separate small apps by itself. If you want to specifically jump from one tab to another instead of going back in stack, use navigation.dispatch(TabActions.jumpTo('Profile')). If pressing something inside tab#1 makes you go to to tab#2 then this screen most likely also belongs to tab#1
also, take a look at backBehavior prop of Tab.Navigator, it might be doing what you want depending on what exactly it is you want https://reactnavigation.org/docs/bottom-tab-navigator/#backbehavior
I'm using bottom tab navigator with 2 stacks as well. I faced similar issue and agree with #Max explanation. Due to my Notification screen is in Stack 1, I have to goBack to Notification after navigating away to Detail screen. After searching for the fix, I'm using this workaround (for v6).
Tab 1 - Stack 1 (Home > Notification screen)
Tab 2 - Stack 2 (Reward Home > Reward Detail screen)
I passed a param when navigating from Notification to RewardDetail. Then I override the headerLeft and use BackHandler to handle Android back function.
Notification.js
navigation.navigate('RewardStack', {
screen: 'RewardDetail',
initial: false,
params:{notification: notification_data_source}
})
RewardDetail.js
const payload = route.params.notification
//1. override headerLeft button
useLayoutEffect(() => {
if(payload)
navigation.setOptions({
headerLeft: () => (
<Button
TouchableComponent={TouchableOpacity}
buttonStyle={{paddingTop:4, paddingLeft:0}}
type='clear'
icon={<Icon name={'chevron-left'} size={30} style={{color:'#FFF'}} />}
onPress={()=>{
navigation.goBack()
navigation.navigate('Notification') //can use this only
}}
/>
)
})
}, [navigation]);
//2. Add BackHandler
useEffect(() => {
const onBackPress = () => {
if (payload) {
navigation.goBack()
navigation.navigate('Notification') //can use this only
return true
} else {
return false
}
}
BackHandler.addEventListener('hardwareBackPress', onBackPress)
return () => BackHandler.removeEventListener('hardwareBackPress', onBackPress)
}, [navigation]);
I can just use navigation.navigate('Notification') to return to Notification but this will cause Detail screen to stay mounted in Stack 2. I want the Stack 2 to return to RewardHome after go back to Notification. Hence I used:
navigation.goBack() //pop screen to RewardHome
navigation.navigate('Notification') //jump to Notification

Back Handler not working when I move back mutiple pages in react native

The scenario is I have 3 screens, from the 3rd screen when I hit the hardware back button, it navigates to 2nd screen. When I again hit the hardware back button, it does not navigate to 1st screen. Instead nothing changes in the screen.
This is how I have used the back handlers.
this.backHandler = BackHandler.addEventListener(
'hardwareBackPress',
this.onTabsBackPress,
);
onTabsBackPress = () => {
this.props.navigation.goBack();
return true;
};
How to resolve this?

React navigation weird back button and pop behavior

I have a nested navigator in my react native App
cost Main = createTabNavigator({
Home:Home,
Challenge:Challenge,
Products:Products,
Options:Options
})
const Options = createStackNavigator({
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
I can navigate from Home screen to Details by simply doing this.props.navigationnavigate('Details')
but when I'm doing this.props.navigation.pop()
it is supposed to take me to last focused screen which was Home screen but it takes me to OptionsScreen
is there a way to go back to Home ?
Try moving Main tab navigator component into stack navigator as below.
const Options = createStackNavigator({
Main:Main,
OptionsScree:OptionsScreen,
Details:Details,
Profile:Profile
})
As Home screen is not present in stack, this.props.navigation.pop() can not pop that screen for you. It pops previous screen in the stack, if none pops the first screen which is in your case is OptionsScreen.

Reset stack after pressing TabBar route

I'm currently stuck with my project, I have a lot of nested navigators and I can't figure out how to reset one of them before navigating.
Here's my navigators structure : ( the Screen X is the same )
MainNavigator
TabBarNavigator
StackNavigator A
Screen A -> navigate to Screen X
Screen B
StackNavigator B
Screen C -> navigate to Screen X
Screen D
StackNavigator C
Screen E -> navigate to Screen X
Screen F
StackNavigator D
Other components
So when i'm navigating from Screen A to screen X, i can still navigate to other navigators ( B, C, D ) because the tabBar is still present and it's good.
However, if I open screen X in Navigator A, then navigate to a screen of Navigator B, when I come back on Navigator A I would like to land on Screen A and not on Screen X as it does right now ( the Screen X is still on top of Navigator A's stack ).
To resume, my nav actualy does :
- Navigator A -> Screen A -> Screen X -> Navigator B -> Screen B -> Go Back to Navigator A but lands on Screen X
And i would like it to do :
- Navigator A -> Screen A -> Screen X -> Navigator B -> Screen B -> Go back to Navigator A and land on Screen A
I tried to set this up in my Screen X navigation option but it does only work on Navigator A :
tabBarOnPress: () => {
navigation.goBack(navigation.state.key)
},
Any help would be appreciated since i've been stuck on this for a while now.
React : 16.0.0
React Native : https://github.com/expo/react-native/archive/sdk-23.0.0.tar.gz
React navigation : ^1.0.0-beta.19
Currently working on iOS simulator
With redux integration you can use the reset method of NavigationActions:
https://reactnavigation.org/docs/navigators/navigation-actions
On the reset method example you'll find:
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Profile'})
]
})
this.props.navigation.dispatch(resetAction)
In react-navigation nesting of tab is bit complex I also faced something similar to this
NavigationActions.reset({
index: 0,
key: null,
actions: [
NavigationActions.navigate({routeName: 'routeNameToNavigate'})
]
});
giving key value solved my problem and navigated me root from nested. Hope this will solve your problem. Here is issue dicussed
https://github.com/react-community/react-navigation/issues/1949