useEffect not firing on state update - reactjs

I am updating some state with useState() in my react native component. Once I have that state set I want to save the details to the server, so I have set that up in an useEffect() hook. To be clear, the setting of the state IS working, and I see the value print to the screen.
However, what I'm noticing is, even though I've set note as a dependency in the dependency array of the useEffect() hook, the function never fires when the state updates. What am I missing here?
const [note, setNote] = useState('');
const dispatch = useDispatch();
useEffect(() => {
if (note) {
console.log('updating note...');
dispatch(updateNote(props.client.id, note));
}
}, [note]);
FYI, I am updating the state inside a TextInput, like so (I had to use onBlur to avoid the issue of react loosing focus on the first character type because I am passing a component within screenOptions of a TabNavigator):
<TextInput
key='note'
style={{
color: '#fff',
fontSize: 16,
width: '100%',
textAlign: 'center',
}}
placeholder='Tap here to share something...'
placeholderTextColor={styles.colors.textPlaceholder}
maxLength={50}
onBlur={(text) => setNote(text)}
defaultValue={note || props?.client?.note?.value}
/>
As I mentioned, this has been a tricky situation because I had to get around react's loss of focus when I rely on onChangeText() or onChange(). I am passing in a CustomHeader - which is a function inside the parent, to a TabNavigator within screenOptions like so:
screenOptions={{
headerShown: true,
headerStyle: {
backgroundColor: Colors.primary,
elevation: 0,
shadowOpacity: 0,
shadowColor: 'transparent',
height: 170,
},
key: 'patient-tab',
headerShadowVisible: false,
tabBarStyle: { backgroundColor: Colors.primary },
headerTintColor: Colors.light,
headerTitle: (props) => <CustomHeader {...props} />, // Passed in here
tabBarActiveTintColor: Colors.light,
tabBarInactiveTintColor: Colors.lightInactive,
tabBarActiveBackgroundColor: Colors.primary,
tabBarInactiveBackgroundColor: Colors.primary,
}}
The full code looks like this:
export const ClientBottomTabNavigator = (props) => {
const [note, setNote] = useState('');
const dispatch = useDispatch();
useEffect(() => {
if (props.client.id && note) {
console.log('updating note...');
dispatch(updateNote(props.client.id, note));
}
}, [props.client.id, note]);
const CustomHeader = () => {
return (
<View>
<View style={{ width: '100%', flexDirection: 'row', justifyContent: 'space-between', marginBottom: 6 }}>
<Feather
name='chevron-left'
size={24}
onPress={() => props.navigation.goBack()}
color={styles.colors.textInverse}
style={{ justifySelf: 'flex-start', alignSelf: 'flex-start', width: '32%', marginBottom: 6 }}
/>
<Text
style={{
color: '#fff',
fontSize: 18,
alignSelf: 'center',
justifySelf: 'center',
fontWeight: 'bold',
}}
>
{props?.client?.firstName} {props?.client?.lastName}
</Text>
<Feather
name='' // Leave this blank
style={{ justifySelf: 'flex-end', alignSelf: 'flex-end', width: '32%' }}
/>
</View>
<View style={{ alignItems: 'center', marginBottom: 6 }}>
<Text style={{ color: '#fff', fontSize: 18, marginBottom: 6 }}>
{convertDiscipline(props?.client?.discipline)}
</Text>
<View>
<TextInput
key='note'
style={{
color: '#fff',
fontSize: 16,
width: '100%',
textAlign: 'center',
}}
placeholder='Tap here to share something…’
placeholderTextColor={styles.colors.textPlaceholder}
maxLength={50}
onBlur={(text) => setNote(text)}
defaultValue={note || props?.client?.note?.value}
/>
</View>
</View>
</View>
);
};
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={{
headerShown: true,
headerStyle: {
backgroundColor: Colors.primary,
elevation: 0,
shadowOpacity: 0,
shadowColor: 'transparent',
height: 170,
},
key: 'client-tab',
headerShadowVisible: false,
tabBarStyle: { backgroundColor: Colors.primary },
headerTintColor: Colors.light,
headerTitle: (props) => <CustomHeader {...props} />, // Passed in here
tabBarActiveTintColor: Colors.light,
tabBarInactiveTintColor: Colors.lightInactive,
tabBarActiveBackgroundColor: Colors.primary,
tabBarInactiveBackgroundColor: Colors.primary,
}}
initialRouteName={'Visits'}
>
<Tab.Screen
name='Visits'
component={VisitsTab}
options={{
tabBarLabel: 'VISITS',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Chart'
component={ChartTab}
options={{
tabBarLabel: 'CHARTS',
tabBarIcon: ({ color, size }) => <FontAwesome name='id-badge' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Goals'
component={GoalsTab}
options={{
tabBarLabel: 'EDIT GOALS',
tabBarIcon: ({ color, size }) => <FontAwesome name='trophy' color={color} size={size} />,
}}
/>
</Tab.Navigator>
);
};

See here https://playcode.io/1106437, it works, but you have onBlur, you need to blur to trigger the action, maybe you need to use onChangeText insted.

Related

React Native, Custom DrawerContent navigator issue

I have a custom DrawerContent component and I am unable to navigate to a screen from it using navigator.navigate('DrawerHelp').
I am still getting this error and I really have no idea how to fix it.
I am trying to navigate from the Help button to its own component called DrawerHelp.
issue The action 'NAVIGATE' with payload {"name":"DrawerHelp"} was not handled by any navigator
This is my code below.
function DrawerComponent() {
return (
<Drawer.Navigator
drawerContentOptions={{activeBackgroundColor: '#efefef', activeTintColor: '#000000'}}
initialRouteName="Tabs"
drawerStyle={{ backgroundColor:'#ffffff', width:'85%', paddingBottom: 50 }}
drawerContent={
props => ( <CustomDrawerContent {...props} /> )
}>
<Drawer.Screen name="Dashboard" component={Tabs} options={{
drawerIcon: config => <Ionicons name={'ios-home'} size={18} color={'#444'} headerTitle="AAA" />,
}} />
<Drawer.Screen name="Help" component={DrawerHelp}
options={{
drawerIcon: config => <Ionicons name={'ios-people-circle-outline'} size={18} color={'#444'}/>,
}}
/>
</Drawer.Navigator>
);
}
export function CustomDrawerContent (props) {
const [ tabs, setTabs ] = useState([
{
name: 'Help',
icon: 'ios-call',
borderColor: '#e7c53f',
backgroundColor: '#fff',
color: '#e7c53f',
fontWeight: '500'
},{
name: 'Share',
icon: 'ios-megaphone',
borderColor: '#e7c53f',
backgroundColor: '#fff',
color: '#e7c53f',
fontWeight: '500'
},{
name: 'Logout',
icon: 'ios-log-out',
borderColor: '#e7c53f',
backgroundColor: '#fff',
color: '#e7c53f',
fontWeight: '500'
}
]);
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<View style={{ padding: 15 }}>
<View style={{
flexDirection: 'row',
justifyContent: 'space-between',
height: 50,
alignItems: 'center'
}}>
{
tabs.map((tab) => {
return (
<TouchableOpacity
key={tab.name}
style={{
height: '100%',
flex: .32,
alignItems: 'center',
borderWidth: .5,
borderColor: tab.borderColor,
backgroundColor: tab.backgroundColor,
borderRadius: 10,
flexDirection: 'row',
justifyContent: 'space-evenly'
}}
onPress={() => {
if(tab.name == 'Logout') {
// navigation.toggleDrawer();
}
if(tab.name == 'Share') {
// onShare();
}
if(tab.name == 'Help') {
props.navigation.navigate('DrawerHelp');
}
}}>
<Ionicons name={tab.icon} size={18} style={{ color: tab.color }} />
<Text style={{ color: tab.color, fontWeight: tab.fontWeight }}>{trans(tab.name, cntx.lang)}</Text>
</TouchableOpacity>
)
})
}
</View>
</View>
</DrawerContentScrollView>
);
}
It is not working because you have defined DrawerComponent with name 'Help'
<Drawer.Screen name="Help" component={DrawerHelp}
options={{drawerIcon: config => <Ionicons name={'ios-people-circle-outline'} size={18} color={'#444'}/>
if(tab.name == 'Help') {
props.navigation.navigate('DrawerHelp'); <== Change here to Help not DrawerHelp
}

How to set the dropdown state to initial whenever I switch Tabs?

I have a bottomtabbar with three screens, all the screens are have a dropdown picker at the header.
Whenever I have my dropdown open and I change the tab screen, my dropdown is still remains opened, however I would like my dropdown to remain closed initially whenever I changed tabs.
My exact code is as follows:
import React, {useEffect, useState} from 'react';
import {ActivityIndicator} from 'react-native';
import {SafeAreaView, View, Image, TouchableOpacity} from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
// bottom tab
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/FontAwesome';
import DropDownPicker from 'react-native-dropdown-picker';
//tabs component
import HomeTabScreen from './HomeTabScreen';
import ConsultationHomeScreen from '../Consult/ConsultationHomeScreen';
import PlansTabScreen from './PlansTabScreen';
import ChatTabScreen from './ChatTabScreen';
import {useSelector, useDispatch} from 'react-redux';
import {
setSelectedChild,
setSelectedChildId,
} from '../../store/actions/userActions';
import {isValidObject} from '../../utils/baseUtils';
import {getChildFromUserChildrenList} from '../../utils/userUtils';
import {setAppReload} from '../../store/actions/HomeActions';
export default function PLHomeScreen(props) {
const {navigation} = props;
const [loading, setLoading] = useState(false);
const Tab = createBottomTabNavigator();
//child related
const [loadApi, setLoadApi] = useState(true);
//Use for all the dispatch actions
const dispatch = useDispatch();
const User = useSelector((state) => state.userReducer.user);
const mSChildId = useSelector((state) => state.userReducer.selectedChildId);
let mChild = getChildFromUserChildrenList(User, mSChildId);
const defaultchildvalue = getChildFromUserChildrenList(User, mSChildId);
const reloadApp = useSelector(
(state) => state.premiumCardActionTypesReducer.reloadApp,
);
console.log('!!!! Reload App !!!!', reloadApp);
useEffect(() => {
if (!isValidObject(mChild)) {
if (!isValidObject(mSChildId)) {
let cid = User.children[0].id;
handleChangeChild(cid);
}
}
if (loadApi == true) {
setLoadApi(false);
setLoading(false);
}
if (reloadApp == true) {
setLoadApi(true);
setLoading(true);
dispatch(setAppReload(false));
}
console.log('!!!! Reload App !!!!', reloadApp);
}, [User, mSChildId, loadApi, reloadApp]);
const handleChangeChild = (id) => {
dispatch(setSelectedChildId(id));
mChild = getChildFromUserChildrenList(User, id);
setLoadApi(true);
setLoading(true);
};
return (
<SafeAreaView
style={{
flex: 1,
alignItems: 'stretch',
justifyContent: 'center',
backgroundColor: '#FE017E',
}}>
<View>
<View
style={{
height: 56,
backgroundColor: '#FE017E',
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<TouchableOpacity
onPress={() => navigation.openDrawer()}
style={{
backgroundColor: '#FE017E',
width: '100%',
height: 40,
padding: 10,
}}
underlayColor="transparent">
<Icon size={20} name="bars" style={{marginLeft: 2}} color="#fff" />
</TouchableOpacity>
</View>
{User != null &&
User.children != undefined &&
User.children != null &&
User.children.length > 0 &&
mChild &&
mChild != undefined &&
mChild != null && (
<DropDownPicker
items={User.children.map((item) => {
return {
label: item.name + '\n' + item.dob_text,
value: item,
icon: () =>
item.pic_url ? (
<Image
source={{
uri: item.pic_url,
}}
style={{height: 30, width: 30, borderRadius: 15}}
/>
) : item.gender === 'male' ? (
<Image
source={{
uri:
'https://cdn3.iconfinder.com/data/icons/materia-human/24/013_042_newborn_infant_child_baby-512.png',
}}
style={{height: 30, width: 30}}
/>
) : (
<Image
source={{
uri:
'https://cdn3.iconfinder.com/data/icons/materia-human/24/013_042_newborn_infant_child_baby-512.png',
}}
style={{height: 30, width: 30}}
/>
),
};
})}
onChangeItem={(item) => {
if (item.value.id != mSChildId) {
handleChangeChild(item.value.id);
}
}}
containerStyle={{
marginLeft: 60,
marginTop: -46,
marginBottom: 10,
height: 40,
}}
defaultValue={defaultchildvalue}
dropDownStyle={{
backgroundColor: '#ffffff',
marginLeft: 40,
borderColor: 'grey',
borderWidth: 1,
borderBottomEndRadius: 0,
borderBottomLeftRadius: 0,
borderBottomStartRadius: 0,
borderBottomRightRadius: 0,
minWidth: 100,
maxWidth: 150,
}}
itemStyle={{
justifyContent: 'flex-start',
fontWeight: 'bold',
fontSize: 20,
borderColor: '#FE017E',
}}
style={{
backgroundColor: '#FE017E',
borderBottomEndRadius: 0,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
borderBottomStartRadius: 0,
borderTopEndRadius: 0,
borderTopLeftRadius: 0,
borderRadius: 0,
borderColor: '#FE017E',
minWidth: 100,
maxWidth: 150,
}}
labelStyle={{
marginLeft: 15,
fontWeight: 'bold',
fontSize: 10,
color: 'black',
textAlign: 'center',
}}
arrowColor={'white'}
activeLabelStyle={{color: '#FE017E'}}
selectedLabelStyle={{color: 'white'}}
/>
)}
</View>
{loading ? (
<ActivityIndicator
color="#FF1493"
size="large"
style={{
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
flexDirection: 'row',
}}
/>
) : (
// <View>
<Tab.Navigator
lazy={true}
initialRouteName="Home"
tabBarOptions={{
labelStyle: {
color: '#FF1493',
fontSize: 12,
},
}}>
<Tab.Screen
name="Home"
// uncommnet below line to see new Home Tab
component={HomeTabScreen}
// uncomment below see old Home Tab
// component={HomeScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({}) => (
<MaterialIcon name="home" color="#FF1493" size={30} />
),
}}
/>
<Tab.Screen
name="Consult"
component={ConsultationHomeScreen}
initialParams={{
mSChildId: mSChildId,
}}
options={{
tabBarLabel: 'Consult',
tabBarIcon: ({}) => (
<FontAwesomeIcon name="stethoscope" color="#FF1493" size={30} />
),
}}
/>
{mChild != null && mChild.is_sc_subscribed == true ? (
<Tab.Screen
name="Chat"
component={ChatTabScreen}
options={{
tabBarLabel: 'Chat',
tabBarIcon: ({}) => (
<MaterialCommunityIcons
name="chat-outline"
color="#FF1493"
size={30}
/>
),
}}
/>
) : (
<Tab.Screen
name="Plans"
component={PlansTabScreen}
options={{
tabBarLabel: 'Plans',
tabBarIcon: ({}) => (
<MaterialCommunityIcons
name="crown-outline"
color="#FF1493"
size={30}
/>
),
}}
/>
)}
</Tab.Navigator>
)}
</SafeAreaView>
);
}
Kindly, let me know how do I let my dropdown remain closed whenever I switch tabs.
Any lead would be appreciated.
Define a controller for your dropdown picker then add a custom buttons to your tab navigator. The custom buttons would allow you implement an onPress listener and in the listener you can run controller.close() to close the dropdown picker.
You can check the npm page if you're not familiar with controllers for the dropdown picker
Edit: Here's how to set a controller as per the npm page:
const [value, setValue] = useState(null);
const [items, setItems] = useState([ {...}, ... ]);
let controller;
<DropDownPicker
items={items}
controller={instance => controller = instance}
onChangeList={(items, callback) => {
new Promise((resolve, reject) => resolve(setItems(items)))
.then(() => callback())
.catch(() => {});
}}
defaultValue={value}
onChangeItem={item => setValue(item.value)}
/>
then you can use the controller wherever you want in your code.

How to access the nested navigator and how to setup properly the authentication flow

I'm quite new on react native this is just a practice project. now I have module regarding on authentication of users and how will navigate dashboard via conditioning the set asyncstorage item if the storage filtered that this storage has true value the user who access will directly move his/her screen to the AuthenticatedDriverScreen.
My Question:
How to navigate in a nested navigator?
How to call the getItem storage item on Navigator Screens?
My Error:
The action 'NAVIGATE' with payload {"name":"BindedScreenComponent","params":{"screen":"DriverDashboard"}} was not handled by any navigator.
Do you have a screen named 'BindedScreenComponent'?
I have already coded some functionality like Navigators Screen, Login Screen Etc. on the next paragraph I will share to you guys the code in every screens. I hope you will understand guys what I mean.
Navigator.JS
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const Bind = createStackNavigator();
const UnauthenticatedScreen = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Login"
component={Login}
options=
{{
headerShown: false,
}}
/>
<Stack.Screen
name="Registration"
component={Register}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTintColor: '#fff',
}}
/>
<Stack.Screen
name="Privacy"
component={PrivacyPolicy}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTitle: 'Privacy Policy',
headerTintColor: '#fff',
}}
/>
<Stack.Screen
name="RegistrationSuccess"
component={RegistrationSuccess}
options=
{{
headerShown: false,
}}
/>
<Stack.Screen
name="ForgotPassword"
component={ForgotPassword}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTitle: 'Forgot Password',
headerTintColor: '#fff',
}}
/>
</Stack.Navigator>
)
}
const BindedScreenComponent = () => {
return (
<Bind.Navigator>
<Bind.Screen
name="DriverDashboard"
component={DriverDashboard}
options={{
headerStyle: {
backgroundColor: '#4ABDFF',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
headerTitle: 'Driver Dashboard'
}}
/>
<Bind.Screen
name="DriverProfile"
component={DriverProfile}
options={{
headerStyle: {
backgroundColor: '#4ABDFF'
},
headerTitleStyle: {
color: '#fff',
},
headerTitle: 'Profile',
headerTintColor: '#fff',
}}
/>
</Bind.Navigator>
)
}
const AuthenticatedDriverScreen = () => {
return (
<Drawer.Navigator drawerContent={props => <CustomDriverDrawer {...props} />} initialRouteName="DriverDashboard">
<Drawer.Screen
name="DriverDashboard"
component={BindedScreenComponent}
options={
{
drawerLabel: 'Home',
drawerIcon: ({ focused, color, size }) => (
<Icon type="font-awesome" name="home" style={{ fontSize: size, color: color }} />
),
}
}
/>
</Drawer.Navigator>
)
}
class Navigator extends React.Component {
constructor(props) {
super(props);
this.state = {
phone_number:'',
password:''
}
}
render() {
const isLogin = false
// try {
// const value = await AsyncStorage.getItem('access_token');
// if (value !== null) console.log(value)
// } catch (error) { // Error retrieving data }
return (
<NavigationContainer>
{isLogin ? <AuthenticatedDriverScreen /> : <UnauthenticatedScreen />}
</NavigationContainer>
)
}
}
export default Navigator;
Login.JS
const UserInfo = {phone_number:'09361876184', password: '123456'}
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
phone_number:'',
password:''
}
}
LoginSubmitFunction = async () => {
const phone_number = this.state.phone_number;
const password = this.state.password;
if(UserInfo.phone_number === phone_number && UserInfo.password === password) {
await AsyncStorage.setItem('userToken', '1');
this.props.navigation.navigate('BindedScreenComponent',{screen:'DriverDashboard'});
}else {
alert('Username or Password is Incorrect!');
}
}
render() {
return (
<SafeAreaView style={[styles.container, { backgroundColor: '#ffff' }]}>
<StatusBar barStyle="dark-content" backgroundColor="#ffff" />
<ScrollView>
<View style={{ marginTop: 60 }}>
<Text style={{ fontSize: 25, fontWeight: 'bold' }}>LOGO</Text>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginTop: 30 }}>Login your credential</Text>
</View>
<View style={{ marginTop: 30 }}>
<TextInput
onChangeText={(phone_number) => this.setState({phone_number})}
value={this.state.phone_number}
placeholder="+63"
keyboardType='numeric'
style={{ height: 50, borderRadius: 5, paddingLeft: 20, borderColor: '#EEEEEE', borderWidth: 1, backgroundColor: '#EEEEEE' }}
/>
<TextInput
onChangeText={(password) => this.setState({password})}
value={this.state.password}
placeholder="Password"
secureTextEntry={true}
style={{ marginTop: 20, borderRadius: 5, paddingLeft: 20, height: 50, borderColor: '#EEEEEE', borderWidth: 1, backgroundColor: '#EEEEEE' }}
/>
</View>
<View style={{ marginTop: 30 }}>
<TouchableOpacity
onPress={this.LoginSubmitFunction}
style={{ height: 70 }} >
<Text style={{ backgroundColor: '#4ABDFF', fontSize: 20, textAlign: 'center', padding: 10, borderRadius: 5, color: '#ffff' }}>Login</Text>
</TouchableOpacity>
</View>
<View style={{ marginTop: 0, alignItems: 'center' }}>
<Text onPress={() => this.props.navigation.navigate('ForgotPassword')} style={{ fontSize: 17 }}>Forgot Password?</Text>
<Text style={{ fontSize: 17, marginTop: 10 }}>Don't have an account yet? <Text style={{ textDecorationLine: 'underline', color: '#4ABDFF', fontWeight: 'bold' }} onPress={() => this.props.navigation.navigate('Registration')}>Register Here</Text></Text>
</View>
</ScrollView>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: { flex: 2, padding: 40 },
});
export default Login;
Output:
The action 'NAVIGATE' with payload {"name":"BindedScreenComponent","params":{"screen":"DriverDashboard"}} was not handled by any navigator.
Because your LoginScreen in UnauthenticatedScreen stack. But UnauthenticatedScreen not contain any screen has name "BindedScreenComponent".
With use isLogin variable to check login, You dont need use NAVIGATE.
await AsyncStorage.setItem('userToken', '1');
userToken is key, and has value is '1' in AsyncStorage.
In your Navigator.JS, You can call it:
const isLogin = await AsyncStorage.getItem('userToken') === '1'
if isLogin = true, it return AuthenticatedDriverScreen . And else, return UnauthenticatedScreen

React Native Navigation Access Navigation from Stack.Screen

I have a stack navigator set up like this:
<Stack.Navigator initialRouteName="Friends">
<Stack.Screen
name="Friends"
component={Friends}
options={{
title: "Friends",
headerStyle: {
backgroundColor: colors.white,
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "700",
color: colors.red,
fontSize: 20,
},
headerRight: () => (
<TouchableOpacity
style={{ marginRight: 20 }}
onPress={() => /*NAVIGATE TO ADD FRIEND*/ }
>
<Ionicons name="md-person-add" size={20} color={colors.red} />
</TouchableOpacity>
),
}}
/>
<Stack.Screen
name="AddFriend"
component={AddFriend}
options={{
title: "Add Friend",
headerStyle: {
backgroundColor: colors.white,
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "700",
color: colors.red,
fontSize: 20,
},
}}
/>
</Stack.Navigator>
As you can see, I have a button on the right side of the header for the Friends screen, and when that button is clicked I'd like to navigate to the Add Friend screen.
However, I don't know how to access the navigation object that you'd typically access via props.navigation inside of the component passed into Stack.Screen.
How can I achieve this?
You can access navigation like below, the options can be a function which takes navigation and route and arguments.
<Stack.Screen
name="Friends"
component={Friends}
options={({navigation})=>({
title: "Friends",
headerStyle: {
backgroundColor: colors.white,
},
headerTintColor: "#fff",
headerTitleStyle: {
fontWeight: "700",
color: colors.red,
fontSize: 20,
},
headerRight: () => (
<TouchableOpacity
style={{ marginRight: 20 }}
onPress={() => navigation.navigate('AddFriend') }
>
<Ionicons name="md-person-add" size={20} color={colors.red} />
</TouchableOpacity>
),
})}
/>

not able to logging out from the app in react native?

i am working on a react native project using redux. i have one stack navigator and one drawer navigator.
i am not able to logout from the app. i want to change store value while logging out. when i am dispatching the action from the logout onPress. it throws error: props.dispatch is not a function. how do i call. i tried many ways it always throwing an error. and how to set all reducers value to intial state while logout? Thank you in advance
App.js
<RootStack.Navigator screenOptions={{
headerShown: false
}}>
{/* <StatusBar backgroundColor={isLoading ? '#000000' : '#F3F3F3'} /> */}
{this.props.data.splashScreen.loading ?
(<RootStack.Screen name={'SplashScreen'} component={SplashScreen} />) :
this.props.data.login.isAuthorized ?
(<RootStack.Screen name="MainNavigator" component={MainNavigator} />)
:
(
<RootStack.Screen name="Login" component={MainStack} />)}
</RootStack.Navigator>
splashScreen and login are reducer store value
MainNavigator.js
const GradientHeader = (props) => (
<View style={{ backgroundColor: "transparent" }}>
<LinearGradient
colors={["#6CCFF6", "#596AB2"]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={
{
/* height: 128 */
/* height: Header.HEIGHT */
}
}
>
<Header {...props} />
</LinearGradient>
</View>
);
const DashboardStackScreen = ({ navigation }) => {
return (
<DashboardStack.Navigator
screenOptions={{
headerTitle: "Good Morning, John",
header: (props) => <GradientHeader {...props} />,
headerLeft: () => (
<TouchableOpacity onPress={navigation.openDrawer} style={{ padding: 20 }}>
<Image source={require("../assets/images/menu_bar.png")} style={{ width: 18, height: 12 }} />
</TouchableOpacity>
),
headerTransparent: true,
headerStyle: {
backgroundColor: "transparent",
},
headerTintColor: "#fff",
headerTitleStyle: { fontFamily: "OpenSans-SemiBold", fontSize: 20 },
}}
>
<DashboardStack.Screen name="Dashboard" component={Dashboard} />
</DashboardStack.Navigator>
);
};
export default ({ navigation }) => {
return (
<Drawer.Navigator
initialRouteName="Dashboard"
drawerContent={(props) => <DrawerContent {...props} />}
hideStatusBar={false}
focused={true}
labelStyle={{ fontSize: 14, fontFamily: "OpenSans-SemiBold" }}
drawerContentOptions={{ activeBackgroundColor: "#F1F1F1", activeTintColor: "#000000", inactiveTintColor: "#818181", itemStyle: { marginLeft: 0, paddingHorizontal: 10, width: "100%", borderRadius: 0 } }}
>
<Drawer.Screen
name="Dashboard"
component={DashboardStackScreen}
options={{
drawerIcon: ({ focused, size }) => <Image source={require("../assets/images/dashboard.png")} style={{ height: 17.78, width: 16 }} resizeMode="contain" />,
}}
/>
<Drawer.Screen
name="My Profile"
component={MyProfileStackScreen}
options={{
drawerIcon: ({ focused, size }) => <Image source={require("../assets/images/profile.png")} style={{ height: 16, width: 16 }} resizeMode="contain" />,
}}
/>
</Drawer.Navigator>
);
};
DrawerContent.js
import { resetData } from "../Storage/Storage";
export function DrawerContent(props) {
return (
<SafeAreaView style={styles.baseContainer}>
<KeyboardAvoidingView behaviour="padding" style={styles.baseContainer}>
<TouchableWithoutFeedback style={styles.baseContainer} onPress={Keyboard.dismiss}>
<View style={styles.baseContainer}>
<TouchableOpacity
style={{ flex: 2, alignItems: "center", justifyContent: "center" }}
onPress={() => {
props.navigation.navigate("Dashboard");
}}
>
<Image source={require("../assets/images/MJB_Logo.png")} style={{ width: 197, height: 59 }} />
</TouchableOpacity>
<View style={{ flex: 5 }}>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
labelStyle={{ fontSize: 14, fontFamily: "OpenSans-SemiBold" }}
activeBackgroundColor="#F1F1F1"
activeTintColor="#000000"
inactiveTintColor="#818181"
label="Logout"
icon={({ focused, color, size }) => {
return <Image source={require("../assets/images/logout.png")} style={{ height: 14.36, width: 14.36 }} resizeMode="contain" />;
}}
onPress={() => resetData()}
/>
</DrawerContentScrollView>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Storage.js
export const resetData = async () => {
try {
//await AsyncStorage.removeItem('isRemembered')
await AsyncStorage.removeItem("userDetails");
} catch (e) {
// saving error
}
};

Resources