Delaying Navigation between screens with react navigation - reactjs

What I want to achieve is when a user clicks on a screen to navigate to another screen, I want the transitioning between the screens to be delayed for 1 second or 2seconds.
I don't know if this is possible in
React navigation
.
I have this code that will transition from home to profile screen.
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
const MyStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Welcome' }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
);
And this is the home screen code
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigation.navigate('Profile', { name: 'Jane' })
}
/>
);
};
And this is the profile screen code.
const ProfileScreen = ({ navigation, route }) => {
return <Text>This is {route.params.name}'s profile</Text>;
};
};
Is possible to move from home screen to profile screen with a delay in time

As #nithinpp suggested, You could achieve this by adding a setTimeout for 2s in the Home screen button onClick.
const HomeScreen = ({ navigation }) => {
return (
<Button
title="Go to Jane's profile"
onPress={() => {
setTimeout(()=> {
navigation.navigate('Profile', { name: 'Jane' });
}, 2000);
}}
/>
);
};
I don't really see a reason to use this code in any application, as this is not at all a good practice to have a hardcoded delay in your application code.

Related

Swipeable component doesn't work in BottomTabNavigator

I have a FlatList inside of a screen that uses BottomTabNavigator from react-navigation-bottom-tabs. Inside of the FlatList are swipeable items, using Swipeable from react-native-gesture-handler. Inside of the tab screens these items aren't swipeable for some reason. However, when I put the screen with the FlatList inside of a StackNavigator screen, and nest that inside of the BottomNavigator tabscreen, it does work. I'm at a loss for why it works this way but not the other way. Does anyone have the slightest clue why this is the case?
Edit: I've seen the issue of not being able to navigate bottom tabs using swipe. I'm not trying to navigate tabs though. Swipeable is applied to items inside a FlatList, that is inside its own component, that is rendered by the Home screen, which in turn is used by the navigator.
The TabsNavigator:
export default function TabsNavigator() {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen
name="List"
component={HomeStack}
options={{
tabBarIcon: ({ focused }) => (
<FontAwesomeIcon
icon={faList}
style={{ color: focused ? "#104543" : "#CCC" }}
/>
),
tabBarActiveTintColor: "#104543",
}}
/>
)
}
The HomeStack (StackNavigator):
export default function StackNavigator() {
const Stack = createStackNavigator();
return (
<Stack.Navigator>
<Stack.Screen
options={{ headerShown: false }}
name="Home"
component={Home}
/>
</Stack.Navigator>
);
}
The Home screen:
export const Home = ({ navigation }) => {
const dispatch = useDispatch();
useEffect(() => {
const fetchUserData = async () => {
const data = await axios.get(
`http://10.0.2.2:80/
`,
{
auth: {
username: "***",
password: "***",
},
}
);
dispatch(setUsersData(data.data));
};
return navigation.addListener("focus", async () => {
await fetchUserData();
});
}, [navigation]);
return (
<View style={styles.container}>
<SearchBarHeader />
//The component with the FlatList in question that contains swipeable items
<SwipeableFlastList />
</View>
);
};
The preferred outcome would be to place the Home screen inside of the Tab.Screen component like this:
<Tab.Screen
name="List"
component={Home}
/>
Per request, the Swipeable component. It's inside of another ListItem component, which inturn is inside a component that renders the flatlist:
<KeyboardAvoidingView style={styles.container}>
<Swipeable
renderRightActions={(
progress: Animated.AnimatedInterpolation,
dragAnimatedValue: Animated.AnimatedInterpolation
) => renderRightActions(progress, dragAnimatedValue, item.Id)}
renderLeftActions={(
progress: Animated.AnimatedInterpolation,
dragAnimatedValue: Animated.AnimatedInterpolation
) => renderLeftActions(progress, dragAnimatedValue, item.Id)}
useNativeAnimations={true}
onSwipeableOpen={() => setSwipeOpen(!swipeOpen)}
onSwipeableClose={() => setSwipeOpen(!swipeOpen)}
>
<TouchableWithoutFeedback>
<AccordionListItem item={item} />
</TouchableWithoutFeedback>
</Swipeable>
</KeyboardAvoidingView>

onPress function for DrawerNavigator

I have created a DrawerNavigator in my react native app which looks like this.
I just dont like the default header that react- native gives. So I wanna access it through an icon. I guess also using the onPress condition
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
// importing of all screens
const Drawer = createDrawerNavigator();
const DrawerContent = () => {
return (
<Drawer.Navigator>
<Drawer.Screen
name="Home"
component={CategoryStack}
/>
<Drawer.Screen name="Aboutus" component={Aboutus} />
<Drawer.Screen name="Interest Recieved" component={InterestRecieved} />
</Drawer.Navigator>
);
};
const Stack = createStackNavigator();
const MainStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Loading"
component={Loading}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
};
export default MainStack;
How do I open it using an onPress of an icon?
Thanks!
React navigation useNavigation hook expose drawer actions - toggleDrawer,openDrawer and closeDrawer event handlers which you can use to open or close drawer.
import React from "react";
import { View, Text, StyleSheet, Pressable } from "react-native";
import { useNavigation } from "#react-navigation/native";
const ToggleDrawer = () => {
const { toggleDrawer,closeDrawer,openDrawer } = useNavigation();
return (
<Pressable onPress={toggleDrawer}>{/** Add your Icon Here */}</Pressable>
);
};
You can check in-depth drawer example
In the header options you can customize the header and add for example an icon on the top left side like this.
useLayoutEffect(() => {
navigation.setOptions({
title: 'ScreenName',
headerLeft: () => (
<View style={{ marginLeft: 15 }}>
<TouchableOpacity onPress={() => navigation.openDrawer()} >
{*INSERT ICON HERE*}
</TouchableOpacity>
</View>
),
})
})

React Native Navigate to Particular Screen When Notification is Clicked

I am trying to implement navigation upon the user click on a notification that they have received. I am successfully receiving the notifications with expo-notifications and accept data (routes) from API but unable to navigate to another screen when user clicks on a notification.
useNotifications:
export default useNotifications = () => {
...
useEffect(() => {
registerForPushNotificationsAsync().then((token) => {
setExpoPushToken(token);
alert(token);
});
notificationListener.current = Notifications.addNotificationReceivedListener(
(notification) => {
setNotification(notification);
console.log(notification);
}
);
responseListener.current = Notifications.addNotificationResponseReceivedListener(
(response) => {
//notification is received OK
console.log("opened");
//here I want to navigate to another screen using rootnavigation
navigation.navigate("Account");
//alert shows fine
alert("ok");
}
);
return () => {
Notifications.removeNotificationSubscription(notificationListener);
Notifications.removeNotificationSubscription(responseListener);
};
}, []);
};
navigator:
const SettingsNavigation = ({ component }) => {
useNotifications();
return (
<Stack.Navigator mode="card" screenOptions={{ headerShown: false }}>
<Stack.Screen
name="Main"
component={component}
options={{ title: "Home" }}
/>
<Stack.Screen
name="Timetable"
component={TimetableScreenBoss}
options={menuOptions("Schedule")}
/>
<Stack.Screen
name="Account"
component={AccountNavigator}
options={menuOptions("Account", false)}
/>
</Stack.Navigator>
);
};
root navigation:
import React from "react";
export const navigationRef = React.createRef();
const navigate = (name, params) =>
navigationRef.current?.navigate(name, params);
export default {
navigate,
};
app.js:
import { navigationRef } from "./app/navigation/rootNavigation"; //rootnavigation
<NavigationContainer navigationRef={navigationRef}>
<CustomNavigator>
</NavigationContainer>
Assuming you are using react-navigation, the NavigationContainer accepts a normal ref prop:
<NavigationContainer ref={navigationRef}>
<CustomNavigator>
</NavigationContainer>
see NavigationContainer docs

React Navigation 5 - How to navigate from headerRight?

i still trying to understand this react navigation 5.0.
Fyi i'm using expo, and right now no problem when navigate from one page to other,
problem is when i put navigation for the headerRight.
i put in headerRight in Stack.Navigator because i want this button to be accessible from other screen.
So basically the problem is,
i want to put logout button in headerRight,
but when i try to put navigation.navigate it sait undefined is not an object (evaluating '_this.props')
Then i try to call a function (handleClick),
problem is undefined is not an object too.
May i know what's wrong with my code?
Below is my full code :
import * as React from 'react';
import { Button, View, Text, TextInput, Image, StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import LoginScreen from './src/pages/auth/Login';
import HomeScreen from './src/pages/auth/HomeScreen';
const Stack = createStackNavigator();
export default function App() {
// handleClick = () => {
// this.props.navigation.navigate('Login');
// }
return (
<NavigationContainer>
<Stack.Navigator mode="modal" initialRouteName="Login" screenOptions={{
headerStyle: {
backgroundColor: '#f4511e',
},
headerRight: () => (
<Button
// only alert is ok, the other is error.
// onPress={() => alert('Success Logout!')}
onPress={this.handleClick}
// onPress={this.props.navigation.navigate('Home')}
title="Logout"
color="#fff"
/>
),
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}>
<Stack.Screen name="Login"
name="Login"
component={LoginScreen}
options={{
title: 'Simple Scorecard',
}} />
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
title: 'Home Menu',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Thanks before
You should try this.
You receive the reference to the router (navigation) by converting the property screenOptions to a function.
screenOptions={({route, navigation}) => ({ // get reference to navigation
headerRight: () => (
<Button
onPress={() => navigation.navigate('Home'); // call .navigate on navigation
/>
)
})}
My answer for that.
you have to pass "navigation", and convert "options" to the function
<Stack.Screen
// some code ...
options={({ navigation }) => ({
headerRight: () => (
<TouchableOpacity onPress={() => navigation.navigate("pageYouWantNavigateTo")} >
// some component ...
</TouchableOpacity>
),
})}
/>

Override Header Title React Navigation V5

I have created a nested tab navigator in my stack navigator as follows:
const Stack = createStackNavigator()
const Tab = createBottomTabNavigator();
function TabNav () {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen}></Tab.Screen>
<Tab.Screen name="Category" component={CategoryScreen}></Tab.Screen>
<Tab.Screen name="Settings" component={SettingsScreen}></Tab.Screen>
</Tab.Navigator>
)
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Tab" component={TabNav}></Stack.Screen>
<Stack.Screen name="Category" component={CategoryScreen}>
</Stack.Screen>
<Stack.Screen
name="SpecialBeerScreen" component= {SpecialBeerScreen}>
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
)
}
However, the header now looks like Tab for each of the screens. How do I override this Header for each of the screens with a custom text, such as Home, Category etc.
Update: This is still valid in react-navigation v6
Use getFocusedRouteNameFromRoute as outlined in the react-navigation docs in the section Setting parent screen options based on child navigator's state to access information of screens in nested navigators.
Change this line
<Stack.Screen name="Tab" component={TabNav}></Stack.Screen>
to the following (adding the options prop):
<Stack.Screen
name="Tab"
component={TabNav}
options={({ route }) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Home';
switch (routeName) {
case 'Category': {
return {
headerTitle: 'Category',
};
}
case 'Settings': {
return {
headerTitle: 'Settings',
};
}
case 'Home':
default: {
return {
headerTitle: 'Home',
};
}
}
}}
/>
You also have to import getFocusedRouteNameFromRoute, so also add:
import { getFocusedRouteNameFromRoute } from '#react-navigation/native';
If I understand your problem correctly, you wanted to change the stack title when the tab is changed. In this case, you may use React Context to control it.
(I also put this code in snack https://snack.expo.io/#gie3d/change-header-from-tab)
edit: 1, I separated it into 3 files and assume that it's all in the same directory.
HomeTitleContext.js
export const HomeTitleContext = React.createContext({
title: 'default title',
setTitle: () => {},
});
App.js
import { HomeTitleContext } from './HomeTitleContext';
export default function App() {
const [title, setTitle] = useState('default title');
return (
<HomeTitleContext.Provider
value={{
title,
setTitle,
}}
>
<HomeTitleContext.Consumer>
{(ctx) => (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Tab"
component={TabNav}
options={{ title: ctx.title }} // The title will be dynamically changed here
/>
<Stack.Screen
name="Category"
component={OtherScreen}
></Stack.Screen>
<Stack.Screen
name="SpecialBeerScreen"
component={OtherScreen}
></Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
)}
</HomeTitleContext.Consumer>
</HomeTitleContext.Provider>
);
}
In your component, for example: HomeScreen, you set up a useFocusEffect and change the title from setTitle which you'll get from the context
HomeScreen.js
import React, { useContext } from 'react';
import { useFocusEffect } from '#react-navigation/native';
import { View, Text } from 'react-native';
import { HomeTitleContext } from './HomeTitleContext';
const HomeScreen = ({ navigation }) => {
const { setTitle } = useContext(HomeTitleContext);
useFocusEffect(() => {
setTitle('this is home');
});
return (
<View>
<Text>Home</Text>
</View>
);
};

Resources