TypeError: undefined is not an object (evaluating 'route.params.prodId') - react-navigation

i want to navigate to other screen while clicking on icon in naviagtion and passing a value but there is error
here is the component from where i want to navigate through passing the values
const UserProductScreen = (props) => {
const userProducts = useSelector((state) => state.products.userProducts);
const dispatch = useDispatch();
const editProductHandler = (id) => {
props.navigation.navigate('editProduct', {
prodId: id,
});
};
return (
<FlatList
data={userProducts}
keyExtractor={(item) => item.id}
renderItem={(itemData) => (
<ProductItem
image={itemData.item.imageUrl}
title={itemData.item.title}
price={itemData.item.price}
onselect={() => {
editProductHandler(itemData.item.id);
}}>
<Button
title="Edit"
onPress={() => {
editProductHandler(itemData.item.id);
}}
/>
<Button
title="Delete"
onPress={() => {
dispatch(productAction.deleteProduct(itemData.item.id));
}}
/>
</ProductItem>
)}
/>
);
};
export default UserProductScreen;
here is the component in which i receive the value passed by other component
const EditProductScreen = ({route, navigation}) => {
const {prodId} = route.params;
const editedProduct = useSelector((state) =>
state.products.userProducts.find((prod) => prod.id === prodId),
);
const [title, setTitle] = useState(editedProduct ? editedProduct.title : '');
const [imageUrl, setImageUrl] = useState(
editedProduct ? editedProduct.imageUrl : '',
);
const [price, setPrice] = useState('');
const [description, setDescription] = useState(
editedProduct ? editedProduct.description : '',
);
const dispatch = useDispatch();
return (
<ScrollView>
<View style={styles.form}>
<View style={styles.formControl}>
<Text style={styles.label}>Title</Text>
<TextInput
style={styles.input}
value={title}
onChangeText={(text) => setTitle(text)}
/>
</View>
<View style={styles.formControl}>
<Text style={styles.label}>Image url</Text>
<TextInput
style={styles.input}
value={imageUrl}
onChangeText={(text) => setImageUrl(text)}
/>
</View>
{editedProduct ? null : (
<View style={styles.formControl}>
<Text style={styles.label}>Price</Text>
<TextInput
style={styles.input}
value={price}
onChangeText={(text) => setPrice(text)}
/>
</View>
)}
<View style={styles.formControl}>
<Text style={styles.label}>Description</Text>
<TextInput
style={styles.input}
value={description}
onChangeText={(text) => setDescription(text)}
/>
</View>
{editedProduct ? (
<Button
title="updated"
onPress={() => {
dispatch(
productsAction.updateProduct(
prodId,
title,
description,
imageUrl,
),
);
}}
/>
) : (
<Button
title="Add product"
onPress={() => {
dispatch(
productsAction.createProduct(
title,
description,
imageUrl,
price,
),
);
}}
/>
)}
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
form: {
margin: 20,
},
formControl: {
width: '100%',
},
label: {
marginVertical: 8,
},
input: {
paddingHorizontal: 2,
paddingVertical: 5,
borderBottomColor: '#ccc',
borderBottomWidth: 1,
},
});
export default EditProductScreen;
here is the file in which navigation code exists
const Stack = createStackNavigator();
const Stackorder = createStackNavigator();
const StackUserProduct = createStackNavigator();
const Drawer = createDrawerNavigator();
const stacknavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Product"
component={ProductOverviewScreen}
options={({navigation}) => ({
headerTitle: 'Products',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<TouchableOpacity onPress={() => navigation.navigate('Cart')}>
<Icon name="cart-plus" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="align-justify" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
})}
/>
<Stack.Screen
name="Detail"
component={ProductDetailScreen}
options={{
headerTitle: 'Detail',
headerTintColor: '#EBF2FA',
headerStyle: {
backgroundColor: '#273469',
},
}}
/>
<Stack.Screen
name="Cart"
component={CartScreen}
options={{
headerTitle: 'Orders',
headerTintColor: '#EBF2FA',
headerStyle: {
backgroundColor: '#273469',
},
}}
/>
<Stack.Screen
name="order"
component={OrderScreen}
options={({navigation}) => ({
headerTitle: 'Order',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="align-justify" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
})}
/>
</Stack.Navigator>
);
};
const stacknavigatorOrder = () => {
return (
<Stackorder.Navigator>
<Stack.Screen
name="order"
component={OrderScreen}
options={({navigation}) => ({
headerTitle: 'Order',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="align-justify" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
})}
/>
</Stackorder.Navigator>
);
};
const stacknavigatorUserProduct = () => {
return (
<StackUserProduct.Navigator>
<Stack.Screen
name="userProduct"
component={UserProductScreen}
options={({navigation}) => ({
headerTitle: 'User Products',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<TouchableOpacity
onPress={() => navigation.navigate('editProduct')}>
<Icon name="pencil" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="align-justify" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
})}
/>
<Stack.Screen
name="editProduct"
component={EditProductScreen}
options={({navigation}) => ({
headerTitle: 'User Products',
headerStyle: {
backgroundColor: '#273469',
},
headerTintColor: '#EBF2FA',
headerRight: () => (
<TouchableOpacity
onPress={() => {
console.log();
}}>
<Icon name="check" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
headerLeft: () => (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<Icon name="align-justify" style={styles.iconstyle} size={25} />
</TouchableOpacity>
),
})}
/>
</StackUserProduct.Navigator>
);
};
const ShopNavigator = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Products">
<Drawer.Screen name="Products" component={stacknavigator} />
<Drawer.Screen name="Order" component={stacknavigatorOrder} />
<Drawer.Screen name="Admin" component={stacknavigatorUserProduct} />
</Drawer.Navigator>
</NavigationContainer>
);
};
const styles = StyleSheet.create({
iconstyle: {
margin: 15,
color: '#EBF2FA',
},
});
export default ShopNavigator;

Related

React Navigation animation from Drawer to Stack

I have some Drawer navigation
<Drawer.Navigator
screenOptions={
drawerStatus ? screenOptions : {...screenOptions, swipeEnabled: false}
}
drawerContent={props => <CustomDrawer {...props} />}
initialRouteName={'Main'}>
{screens.map(screen => (
<Drawer.Screen
key={screen.name}
name={screen.name}
component={screen.component}
/>
))}
</Drawer.Navigator>
And in this Drawer I have a nested screen "Post Detail"
<Stack.Navigator
screenOptions={{
headerShown: false,
}}>
<Stack.Screen name={'PostDetail'} component={PostDetail} />
</Stack.Navigator>
If I navigate from Drawer to nested StackScreen or go back to Drawer, I don`t catch animation transition.
Apparently, using only the 'createDrawerNavigator', it is not possible to change the screen transition animation. For this, you must create a 'createStackNavigator', inserting your DrawerNavigator in your 'Home'. Do like:
import React from 'react';
import Home from '../pages/home/home';
import HeaderHome from '../shared/headerHome';
import Configuracoes from '../pages/configuracoes';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
import { DrawerContent } from '../shared/drawerContent';
const Drawer = createDrawerNavigator();
const Content = (navigation: any) => (
<Drawer.Navigator
drawerContent={props => <DrawerContent {...props} />}
>
<Drawer.Screen name="HomeDrawer" component={Home}
options={{
header: (props) => <HeaderHome value={props} /> //My cystom Header
}}
/>
</Drawer.Navigator>
);
const Stack = createStackNavigator();
const MyStack: React.FC = () => {
return (
<Stack.Navigator
screenOptions={({ route, navigation }) => ({
headerMode: "float",
animationEnabled: true
})}
>
<Stack.Screen name="Home" component={Content} //The name used cannot be identical to the one used in Drawer.Navigator
options={{ headerShown: false }}
/>
<Stack.Screen name="Configuracoes" component={Configuracoes}
options={{
title: "Title page",
headerStyle: {
backgroundColor: "red",
},
headerTintColor: "#fff"
}}
/>
</Stack.Navigator>
);
}
export default MyStack;

Getting undeifined value when passing data from one screen to another screen in react-native

When I am trying to pass data from Login screen to MyProfile screen then I got undefined value.
I am confused that why I am getting undefined value ?
Here is code of my main navigation files.
route.js
import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer, getFocusedRouteNameFromRoute } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { createDrawerNavigator } from "#react-navigation/drawer";
import LoginScreen from "./../screens/Login/index.js";
import MyProfileScreen from "../screens/MyProfile/index.js";
import AboutUsScreen from "../screens/AboutUs/index.js";
import SettingScreen from "../screens/Setting/index.js";
import { Image, StyleSheet, View, TouchableOpacity } from "react-native";
import { heightPercentageToDP as hp, widthPercentageToDP as wp } from 'react-native-responsive-screen';
import { RFValue } from "react-native-responsive-fontsize"
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();
const NavigationDrawerStructure = (props) => {
const toggleDrawer = () => {
props.navigationProps.toggleDrawer();
}
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={() => toggleDrawer()}>
<Image
source={{ uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png' }}
style={{
width: 25,
height: 25,
marginLeft: 5
}}
/>
</TouchableOpacity>
</View>
)
}
const geHeaderTitle = (route) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'MyProfileScreen';
switch (routeName) {
case 'MyProfileScreen':
return 'Profile';
case 'AboutUsScreen':
return 'AboutUs';
case 'SettingScreen':
return 'Setting';
}
}
const BottomTab = () => {
return (
<Tab.Navigator initialRouteName="MyProfileScreen"
tabBarOptions={{
activeTintColor: "red",
labelStyle: {
fontSize: RFValue('14'),
marginTop: 5
},
style: { height: hp('11') }
}}
>
<Tab.Screen
name="MayProfileScreen"
component={MyProfileScreen}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ focused }) => (
focused ?
<Image source={require('./../../asstes/images/profile.png')} style={styles.activeImg} /> :
<Image source={require('./../../asstes/images/profile.png')} style={styles.deActiveImg} />
)
}}
/>
<Tab.Screen
name="AboutUsScreen"
component={AboutUsScreen}
options={{
tabBarLabel: 'AboutUs',
tabBarIcon: ({ focused }) => (
focused ?
<Image source={require('./../../asstes/images/aboutus.png')} style={styles.activeImg} /> :
<Image source={require('./../../asstes/images/aboutus.png')} style={styles.deActiveImg} />
)
}}
/>
<Tab.Screen
name="SettingScreen"
component={SettingScreen}
options={{
tabBarLabel: 'Setting',
tabBarIcon: ({ focused }) => (
focused ?
<Image source={require('./../../asstes/images/setting.png')} style={styles.activeImg} /> :
<Image source={require('./../../asstes/images/setting.png')} style={styles.deActiveImg} />
)
}}
/>
</Tab.Navigator>
)
}
const HomeStack = ({ navigation }) => {
return (
<Stack.Navigator initialRouteName="LoginScreen">
<Stack.Screen name="LoginScreen" component={LoginScreen} options={{ headerShown: false }} />
<Stack.Screen name="MyProfileScreen" component={BottomTab}
options={({ route }) => ({
headerTitle: geHeaderTitle(route),
headerLeft: () => (
<NavigationDrawerStructure navigationProps={navigation} />
),
title: 'Profile',
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' }
})}
/>
<Stack.Screen name="AboutUsScreen" component={AboutUsScreen}
options={{
title: 'AboutUS',
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' }
}} />
<Stack.Screen name="SettingScreen" component={SettingScreen}
options={{
title: 'Setting',
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' }
}}
/>
</Stack.Navigator>
)
}
const AboutUsStack = ({ navigation }) => {
return (
<Stack.Navigator initialRouteName="AboutUsScreen"
screenOptions={{
headerLeft: () => (
<NavigationDrawerStructure navigationProps={navigation} />
),
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' }
}}
>
<Stack.Screen name="AboutUsScreen" component={AboutUsScreen} options={{ title: 'AboutUs' }} />
</Stack.Navigator>
)
}
const SettingStack = ({ navigation }) => {
return (
<Stack.Navigator initialRouteName="SettingScreen"
screenOptions={{
headerLeft: () => (
<NavigationDrawerStructure navigationProps={navigation} />
),
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
headerTitleStyle: { fontWeight: 'bold' }
}}
>
<Stack.Screen name="SettingScreen" component={SettingScreen} options={{ title: 'Setting', }} />
</Stack.Navigator>
)
}
const Navigation = () => {
return (
<NavigationContainer>
<Drawer.Navigator
drawerContentOptions={{
activeTintColor: '#e91e63',
itemStyle: { marginVertical: 5 }
}}
>
<Drawer.Screen name="HomeStack" options={{ drawerLabel: 'Profile' }} component={HomeStack} />
<Drawer.Screen name="AboutUsStack" component={AboutUsStack} options={{ drawerLabel: 'AboutUs' }} />
<Drawer.Screen name="SettingStack" component={SettingStack} options={{ drawerLabel: 'Setting' }} />
</Drawer.Navigator>
</NavigationContainer>
)
}
const styles = StyleSheet.create({
activeImg: {
height: hp('4.8'), width: wp('8.5'), marginTop: 10, borderRadius: 12, tintColor: 'red'
},
deActiveImg: {
height: hp('4.8'), width: wp('8.5'), marginTop: 10, borderRadius: 12, tintColor: 'gray'
}
})
export default Navigation;
I am calling below function when user click on Login button.
Here is some lines of code that how I am trying to pass data from Login screen to MyProfile screen
Login screen
const resetTextInput = () => {
setName(null);
setPassword(null);
navigation.navigate('MyProfileScreen', { userName: name, userPwd: password,});
}
<TouchableOpacity style={styles.loginBtn} onPress={() => { resetTextInput() }}>
<Text style={styles.loginBtnTxt}>Login</Text>
</TouchableOpacity>
Here is some lines of code that how I am trying to get data from Login screen to MyProfile screen.
MyProfle screen
useEffect(() => {
console.log("username is-->",JSON.stringify(route?.params?.userName));
console.log("userpassword is-->",JSON.stringify(route?.params?.userPwd));
});
Perhaps pass route.params? as an argument inside your useEffect?
useEffect(() => {
...
},[route.params?]);
That way it'll apply the effect when you navigate into it.
Do you have a multiple stack navigator? If you are at different stack navigator and you want to pass params to a screen from different stack navigator, you have to specify the screen.
For example you are at the AuthStack and you want to navigate to MyProfileScreen from the ProfileStack:
navigation.navigate('ProfileStack', { screen: 'MyProfileScreen', params: { //data here } });
if not, I think you got a typo in your BottomTab component. Change the name of the first tab from "MayProfileScreen" to "MyProfileScreen".
then use this to navigate:
navigation.navigate('MyProfileScreen', { //params here });

How to validate in react-native by using formik and yup?

How do i show error messages here by using formik and yup?
Suppose i want to show an error message for Customer name.
How to do this?
import React, { Component } from 'react';
import { Text,Alert, TextInput, View, StyleSheet, KeyboardAvoidingView, ActivityIndicator, TouchableOpacity, Image, Animated, Easing,} from 'react-native';
import { Button } from 'react-native-elements'
import PropTypes from 'prop-types';
import Dimensions from 'Dimensions';
import { Router, Scene, Actions } from 'react-native-router-flux';
import * as Yup from 'yup';
import { Formik } from 'formik';
import eyeImg from '../images/eye_black.png';
const DEVICE_WIDTH = Dimensions.get('window').width;
const DEVICE_HEIGHT = Dimensions.get('window').height;
I have declared initialValues also.
Please help me.
const initialValues = {
customer_name: "",
mobile: "",
password: "",
repassword: "",
email_address: "",
company_id: "",
profile_image: "",
licence_number: "",
user_status: "Active",
};
Here are my error messages.
const customervalidation = Yup.object().shape({
customer_name: Yup.string().required("Please enter name"),
email_address: Yup.string()
.required("Please enter email address")
.email('Please enter a valid email'),
mobile: Yup.string().required("Please enter mobile"),
password: Yup.string().required("Please enter password"),
repassword: Yup.string().oneOf([Yup.ref('password'), null], 'Passwords must match')
});
export default class Form extends Component {
constructor(props) {
super(props);
this.state = {
customer_name: '',
mobile: '',
password: '',
cpassword: '',
email_address: '',
showPass: true,
showConfPass: true,
press: false,
};
this.showPass = this.showPass.bind(this);
this.showConfPass = this.showConfPass.bind(this);
this._onPress = this._onPress.bind(this);
}
showPass() {
//Alert.alert('Credentials', `${this.state.press}`);
this.state.press === false
? this.setState({showPass: false, press: true})
: this.setState({showPass: true, press: false});
}
showConfPass() {
this.state.press === false
? this.setState({showConfPass: false, press: true})
: this.setState({showConfPass: true, press: false});
}
This is actually my API for sign up section.
onSignup() {
const { customer_name, mobile, password, cpassword, email_address } = this.state;
Alert.alert('Credentials', `${customer_name} + ${mobile} + ${password} + ${cpassword} + ${email_address}`);
fetch('url', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
customer_name: this.state.customer_name,
mobile: this.state.mobile,
email_address: this.state.email_address,
password: this.state.password,
})
}).then((response) => response.json())
.then((responseJson) => {
alert('Success');
}).catch((error) => {
alert('Error');
});
}
_onPress() {
if (this.state.isLoading) return;
this.setState({isLoading: true});
Animated.timing(this.buttonAnimated, {
toValue: 1,
duration: 200,
easing: Easing.linear,
}).start();
setTimeout(() => {
this._onGrow();
}, 2000);
setTimeout(() => {
Actions.forgotpwdScree();
this.setState({isLoading: false});
this.buttonAnimated.setValue(0);
this.growAnimated.setValue(0);
}, 2300);
}
I have added formik here . I want to show error messages during setfieldtouch,onblur and form submit
render() {
return (
<Formik initialValues= {initialValues} validationSchema={customervalidation}>
{({ values, errors, isValid, touched, setFieldTouched, isSubmitting }) => {
return(
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>NAME</Text>
<TextInput
value={this.state.customer_name}
onChangeText={(customer_name) => this.setState({ customer_name })}
placeholder={'Name'}
style={styles.input}
/>
</View>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>PHONE NUMBER</Text>
<TextInput
value={this.state.mobile}
onChangeText={(mobile) => this.setState({ mobile })}
placeholder={'Mobile Number'}
style={styles.input}
/>
</View>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>PASSWORD</Text>
<TextInput
value={this.state.password}
secureTextEntry={this.state.showPass}
onChangeText={(password) => this.setState({ password })}
placeholder={'PASSWORD'}
returnKeyType={'done'}
autoCapitalize={'none'}
autoCorrect={false}
style={styles.input}
/>
</View>
<TouchableOpacity
activeOpacity={0.7}
style={styles.btnEye}
onPress={this.showPass}>
<Image source={eyeImg} style={styles.iconEye} />
</TouchableOpacity>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>CONFIRM PASSWORD</Text>
<TextInput
value={this.state.cpassword}
secureTextEntry={this.state.showConfPass}
onChangeText={(cpassword) => this.setState({ cpassword })}
placeholder={'CONFIRM PASSWORD'}
returnKeyType={'done'}
autoCapitalize={'none'}
autoCorrect={false}
style={styles.input}
/>
</View>
<TouchableOpacity
activeOpacity={0.7}
style={styles.btnEye2}
onPress={this.showConfPass}>
<Image source={eyeImg} style={styles.iconEye} />
</TouchableOpacity>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>EMAIL ID</Text>
<TextInput
value={this.state.email_address}
onChangeText={(email_address) => this.setState({ email_address })}
placeholder={'Email Address'}
style={styles.input}
/>
</View>
<View style={styles.inputcontainerB}>
<Text style={styles.textR} >I AGREE WITH UP TERMS</Text>
<Button
large
title='SIGN UP'
icon={{name: 'lock', type: 'font-awesome'}}
onPress={this.onSignup.bind(this)}
/>
</View>
</KeyboardAvoidingView>
);
}}
</Formik>
);
}
}
You can use: values, handleSubmit, handleChange, errors, touched, handleBlur, from the render prop in formik component, Formik lib already does the updates to the form values, so there is no need to use state for this, for example, for the customer_name you need to add a Text component to show the error.
<Formik
initialValues={initialValues}
onSubmit={this.onSignup}
validationSchema={customervalidation}
render={({
values,
handleSubmit,
handleChange,
errors,
touched,
handleBlur
}) => (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.inputcontainer}>
<Text style={styles.textlabel}>NAME</Text>
<TextInput
value={values.customer_name}
onBlur={handleBlur('customer_name')}
onChangeText={handleChange('customer_name')}
placeholder={'Name'}
style={styles.input}
/>
<Text>{touched.customer_name && errors.customer_name}</Text>
</View>
...
<Button
large
title='SIGN UP'
icon={{name: 'lock', type: 'font-awesome'}}
onPress={handleSubmit}
/>
</KeyboardAvoidingView>
)
/>
the handleSubmit prop will pass the function declared in the onSubmit prop to the render, which will send the param values, which in your case will have the updated values declared in initialValues
{
customer_name: "",
mobile: "",
password: "",
repassword: "",
email_address: "",
company_id: "",
profile_image: "",
licence_number: "",
user_status: "Active"
}

react native: animation not triggering in release mode

I am trying my react native app on android and iOS using the release mode. unfortunately, there is an animation that doesn't trigger in release mode which works perfectly on debug mode.
i have tried to use the 'useNativeDriver: true' which improved the animation on android but didn't fix the issue
for ref:
"react-native": "0.56.0"
my Drawer.js
toggle = () => {
Animated.timing(this.x_translate, {
toValue: this.state.drawerOpen ? 0 : 1,
duration: this.state.animationDuration,
useNativeDriver: true
}).start();
this.setState({ drawerOpen: !this.state.drawerOpen })
}
render() {
const menu_moveX = this.x_translate.interpolate({
inputRange: [0, 1],
outputRange: [-this.state.width, 0]
});
return (
<Animated.View style={[this.props.style, styles.drawer, {
transform: [
{
translateX: menu_moveX
}
]
}]}>
<ImageBackground
source={require('../images/background.png')}
style={{ width: '100%', height: '100%', alignItems: 'center' }}
>
<View style={styles.blank}></View>
<AutoHeightImage source={require('../images/image.png')} width={0.7 * this.state.width} />
<LineDashboard navigate={this.props.navigate} items={[this.menu[0], this.menu[1]]} sizeIcon={30} />
<LineDashboard navigate={this.props.navigate} items={[this.menu[2], this.menu[3]]} sizeIcon={30} />
<LineDashboard navigate={this.props.navigate} items={[this.menu[4], this.menu[5]]} sizeIcon={30} />
</ImageBackground>
</Animated.View>
)
}
my dashboard.js
componentDidMount() {
this.props.navigation.setParams({
handleThis: () => {
console.log(this.drawer);
this.setState({ loaded: true })
this.drawer.toggle();
}
});
}
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle: 'Home Page',
headerLeft: (
<TouchableOpacity
onPress={() => {
params.handleThis();
}}
style={{ marginLeft: 20 }}
>
<Icon name="menu" size={25} color="black" />
</TouchableOpacity>
),
headerRight: (
<TouchableOpacity
onPress={() => {
console.log(navigation);
// navigation.goBack(null)
navigation.navigate('Login');
}}
style={{ marginRight: 20 }}
>
<Text style={{ color: 'red' }}>Log Out</Text>
</TouchableOpacity>
)
}
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.page}>
<ScrollView>
<View style={styles.pageContainer}>
<View style={{ height: 30 }} />
<AutoHeightImage source={require('../images/patient_primary_logo_white.png')} width={0.7 * width} />
<View style={styles.separator} />
<DashboardNotificationTile title={'Your Notifications'} onPress={() => navigate('Notifications')}>
<Text>You have 2 new notifications</Text>
<Text>Please click to see more</Text>
</DashboardNotificationTile>
<DashboardTile title={'Your Visits'}>
<Text>You have 1 upcoming visit</Text>
<SimpleButton onPress={() => navigate('ToBook')} title='View All Visits' width={'100%'} style={{ marginTop: 16 }} color={'green'}/>
</DashboardTile>
<DashboardTile title={'Your Expense Claims'}>
<Text>You have 2 open expense claims</Text>
<SimpleButton onPress={() => navigate('Open')} title='View All Expense Claims' width={'100%'} style={{ marginTop: 16 }} />
</DashboardTile>
</View>
</ScrollView>
<DrawerDashboard navigate={navigate} onRef={(ref) => this.drawer = ref} style={this.state.loaded ? { opacity: 1 } : { opacity: 0 }} />
</View >
)
}
in Dashboard.js, i have a headerLeft that should trigger the function handleThis() which doesn't seems to be doing. however, when pressed, the TouchableOpacity component stay 'selected' rather than coming back to its original state.
any suggestion?
thanks
EDIT:
the issue occurs at any time when the debugger is not on. sorry i just discovered it right now. The animation works perfectly if the remote JS debugger is launched.
So, i thought the issue may be the processing time, as the app is working slower when the debugger is on, maybe my handleThis() function was not loaded...
So, I moved the setParams() from the ComponentDidMount to WillMount.
didn't worked :\
Any suggestion?

Why is react-native-material-dropdown so slow in the way I use it to edit and add majors?

My app drop-downs are pretty slow. It especially takes a long time if i go into the Settings Screen and try to change my major. Or anything dealing with adding or editing a major in this specific screen. I really need to make adding or editing a major much faster. I am not sure the reason why editing or adding a major is taking too long. And I am not sure about how to go at making adding and editing a major much faster. So I am posting the entire component and I am commenting parts that deal with adding or editing a major. I am using react-native-material-dropdown.
Here is the entire component code:
import React from 'react';
import PropTypes from 'prop-types';
import { View, ScrollView, Text, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { compose, withStateHandlers } from 'recompose';
import { Dropdown } from 'react-native-material-dropdown';
import { Icon } from 'react-native-material-ui';
import R from 'ramda';
import { ConnectivityRenderer } from 'react-native-offline';
import NetworkConnectivity from '../error/NetworkConnectivity';
import { toArray } from '../selectors';
import { Container, Switch, SwitchOption } from './common';
import { editStudent } from '../actions';
const propTypes = {
toolbar: PropTypes.elem,
loading: PropTypes.bool,
university: PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
}),
universities: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
})
),
degrees: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
})
),
studentDegrees: PropTypes.arrayOf(
PropTypes.shape({
index: PropTypes.number,
track: PropTypes.string,
})
),
errors: PropTypes.shape({
university: PropTypes.string,
degree: PropTypes.string,
}),
year: PropTypes.string,
onUniversityChange: PropTypes.func,
onTermChange: PropTypes.func,
onDegreeChange: PropTypes.func,
onYearChange: PropTypes.func,
onTrackChange: PropTypes.func,
onAddDegree: PropTypes.func,
onDone: PropTypes.func,
};
const contextTypes = {
uiTheme: PropTypes.object.isRequired,
};
const validate = state => {
const result = {};
if (!state.university.id) {
result.university = 'You should select an university';
}
return result;
};
const enhance = compose(
connect(
({ user, universities, degrees }) => ({
studentId: user.id,
user,
universities: toArray(universities),
degrees: toArray(degrees),
}),
{ editStudent }
),
withStateHandlers(
props => {
return {
university: props.user.university || {},
year: props.user.academicClass || 'freshman',
studentDegrees: R.isEmpty(props.degrees)
? []
: R.isEmpty(props.user.studentDegrees)
? [{ degree_id: props.degrees[0].id, track: 'Major' }]
: R.values(props.user.studentDegrees),
errors: {},
};
},
{
onUniversityChange: () => (value, index, data) => ({
university: data[index],
}),
onYearChange: () => year => ({ year }),
onTrackChange: state => ({ idx, track }) => ({
studentDegrees: R.update(
idx,
R.assoc('track', track, state.studentDegrees[idx]),
state.studentDegrees
),
}),
// Fucntion dealing with degree change
onDegreeChange: (state, props) => ({ idx, index }) => ({
studentDegrees: R.update(
idx,
R.assoc(
'degree_id',
props.degrees[index].id,
state.studentDegrees[idx]
),
state.studentDegrees
),
}),
// Function dealing with degree adding
onAddDegree: (state, props) => () => ({
studentDegrees: R.append(
{
degree_id: props.degrees[0].id,
track: 'Major',
},
state.studentDegrees
),
}),
onRemoveDegree: state => idx => ({
studentDegrees: [
...state.studentDegrees.slice(0, idx),
...state.studentDegrees.slice(idx + 1),
],
}),
// When the user is done with settings.
// This function communicates with the back end to save things in the remote database
onDone: (state, { studentId, editStudent }) => () => {
const errors = validate(state);
if (Object.keys(errors).length !== 0) {
return { errors };
}
editStudent(
studentId,
state.year,
state.university.id,
state.studentDegrees
);
},
}
)
);
// The Settings Component
const FormUserSettings = (props, context) => {
const styles = getStyles(props, context);
return (
<ConnectivityRenderer>
{isConnected => (
isConnected ? (
<Container>
{React.cloneElement(props.toolbar, {
onRightElementPress: props.onDone,
})}
<ScrollView style={styles.container}>
<Text
style={[
styles.title,
props.errors.university ? styles.titleError : {},
]}
>
University
</Text>
// Selecting a university
<Dropdown
label="Select university..."
data={props.universities.map(u => ({ id: u.id, value: u.name }))}
onChangeText={props.onUniversityChange}
value={props.university.name}
/>
{props.errors.university &&
<Text style={styles.errorMessage}>
{props.errors.university}
</Text>}
<View style={{ height: 16 }} />
<Text style={styles.title}>Current Year</Text>
<View style={{ height: 8 }} />
<Switch
value={props.year}
onChange={props.onYearChange}
selectedColor={styles.switchSelectedColor}
unselectedColor={styles.switchUnselectedColor}
>
<SwitchOption text="Freshman" value="freshman" />
<SwitchOption text="Sophomore" value="sophomore" />
<SwitchOption text="Junior" value="junior" />
<SwitchOption text="Senior" value="senior" />
</Switch>
<View style={{ height: 16 }} />
<Text
style={[styles.title, props.errors.degree ? styles.titleError : {}]}
>
Major / Minors
</Text>
{!R.isEmpty(props.degrees) &&
props.studentDegrees.map((sd, idx) => {
const degree = R.find(R.propEq('id', sd.degree_id), props.degrees);
return (
<View
key={`sd-${idx}`}
style={{ flex: 1, height: 96, marginTop: 24 }}
>
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'flex-end',
}}
>
<View style={{ flex: 1 }}>
<Dropdown
style={{ flex: 1 }}
label="Select degree..."
data={props.degrees.map(d => ({
id: d.id,
value: d.name,
}))}
onChangeText={(value, index) =>
props.onDegreeChange({ idx, index })}
value={degree ? degree.name : ''}
/>
</View>
{props.studentDegrees.length !== 1 &&
<TouchableOpacity
style={{ marginBottom: 8, paddingLeft: 24 }}
onPress={() => props.onRemoveDegree(idx)}
>
<Icon name="delete" size={24} />
</TouchableOpacity>}
</View>
<Switch
value={sd.track}
onChange={track => props.onTrackChange({ idx, track })}
selectedColor={styles.switchSelectedColor}
unselectedColor={styles.switchUnselectedColor}
>
<SwitchOption text="Major" value="Major" />
<SwitchOption text="Minor" value="Minor" />
<SwitchOption text="Certificate" value="Cert" />
</Switch>
</View>
);
})}
<TouchableOpacity style={{ padding: 10 }} onPress={props.onAddDegree}>
<Text style={styles.addDegreeText}>+ Degree</Text>
</TouchableOpacity>
</ScrollView>
</Container>
) : (
<Container>
{React.cloneElement(props.toolbar, {
onRightElementPress: props.onDone,
})}
<NetworkConnectivity />
<ScrollView style={styles.container}>
<Text
style={[
styles.titleDisabled,
props.errors.university ? styles.titleError : {},
]}
>
University
</Text>
<Dropdown
label=""
data={props.universities.map(u => ({ id: u.id, value: u.name }))}
onChangeText={props.onUniversityChange}
value={props.university.name}
disabled={true}
editable={false}
/>
{props.errors.university &&
<Text style={styles.errorMessage}>
{props.errors.university}
</Text>}
<View style={{ height: 16 }} />
<Text style={styles.titleDisabled}>Current Year</Text>
<View style={{ height: 8 }} />
<Switch
value={props.year}
onChange={props.onYearChange}
selectedColor={styles.disabledSwitchSelectedColor}
unselectedColor={styles.switchUnselectedColor}
>
<SwitchOption text="Freshman" value="freshman" />
<SwitchOption text="Sophomore" value="sophomore" />
<SwitchOption text="Junior" value="junior" />
<SwitchOption text="Senior" value="senior" />
</Switch>
<View style={{ height: 16 }} />
<Text
style={[styles.titleDisabled, props.errors.degree ? styles.titleError : {}]}
>
Major / Minors
</Text>
// The problem of slowness starts here
// I feel like something here should be improved
{!R.isEmpty(props.degrees) &&
props.studentDegrees.map((sd, idx) => {
const degree = R.find(R.propEq('id', sd.degree_id), props.degrees);
return (
<View
key={`sd-${idx}`}
style={{ flex: 1, height: 96, marginTop: 24 }}
>
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'flex-end',
}}
>
<View style={{ flex: 1 }}>
<Dropdown
style={{ flex: 1 }}
label="Select degree..."
data={props.degrees.map(d => ({
id: d.id,
value: d.name,
}))}
disabled={true}
editable={false}
onChangeText={(value, index) =>
props.onDegreeChange({ idx, index })}
value={degree ? degree.name : ''}
/>
</View>
</View>
<Switch
value={sd.track}
onChange={track => props.onTrackChange({ idx, track })}
selectedColor={styles.disabledSwitchSelectedColor}
unselectedColor={styles.switchUnselectedColor}
>
<SwitchOption text="Major" value="Major" />
<SwitchOption text="Minor" value="Minor" />
<SwitchOption text="Certificate" value="Cert" />
</Switch>
</View>
);
})}
<TouchableOpacity disabled={true} style={{ padding: 10 }} onPress={props.onAddDegree} disabled={true}>
<Text style={styles.addDegreeTextDisabled}>+ Degree</Text>
</TouchableOpacity>
</ScrollView>
</Container>
)
)}
</ConnectivityRenderer>
);
};
FormUserSettings.contextTypes = contextTypes;
FormUserSettings.propTypes = propTypes;
export default enhance(FormUserSettings);

Resources