undefined is not an object (evaluating '_this.props.navigation') Expo React Native - react-native

I am getting undefined is not an object evaluating _this.props.navigation. Here is my code. I want to use Flatlist to call the screen 'PlaceorderScreen.js' number of times from the component 'NearbyLSP.js' present in the 'HomeScreen.js'. Also I had referred many solutions for the above problem but yet I didn't get how to get through it. I am a beginner in react-native, So I had used expo for app development.
HomeScreen.js
import React from "react";
import {
View,
Text,
StyleSheet,
SafeAreaView,
TextInput,
Platform,
StatusBar,
ScrollView,
TouchableOpacity,
Dimensions,
Animated,
} from "react-native";
import Icon from 'react-native-vector-icons/Ionicons'
import Category from './Category'
import Expressmode from './Expressmode'
import { FlatList } from "react-native-gesture-handler";
import NearbyLSP from "./NearbyLSP";
const { width } = Dimensions.get('window')
const data = [
{id:'1',name:'LSP1',phone:'1234',email:'abc#gmail.com'},
{id:'2',name:'LSP2',phone:'0234',email:'abc2#gmail.com'},
{id:'3',name:'LSP3',phone:'2234',email:'abc3#gmail.com'}
]
const renderList = ((item) =>{
return <TouchableOpacity
onPress={()=> this.props.navigation.navigate('PlaceOrder')}
activeOpacity={0.7}>
<NearbyLSP name={item.name}/>
</TouchableOpacity>
})
export default class HomeScreen extends React.Component {
componentDidMount() {
this.scrollY = new Animated.Value(0)
this.startHeaderHeight = 80
this.endHeaderHeight = 50
if (Platform.OS == 'android') {
this.startHeaderHeight = 100 + StatusBar.currentHeight
this.endHeaderHeight = 70 + StatusBar.currentHeight
}
this.animatedHeaderHeight = this.scrollY.interpolate({
inputRange: [0, 50],
outputRange: [this.startHeaderHeight, this.endHeaderHeight],
extrapolate: 'clamp'
})
this.animatedOpacity = this.animatedHeaderHeight.interpolate({
inputRange: [this.endHeaderHeight, this.startHeaderHeight],
outputRange: [0, 1],
extrapolate: 'clamp'
})
this.animatedTagTop = this.animatedHeaderHeight.interpolate({
inputRange: [this.endHeaderHeight, this.startHeaderHeight],
outputRange: [-30, 10],
extrapolate: 'clamp'
})
this.animatedMarginTop = this.animatedHeaderHeight.interpolate({
inputRange: [this.endHeaderHeight, this.startHeaderHeight],
outputRange: [50, 30],
extrapolate: 'clamp'
})
}
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<Animated.View style={{ height: this.animatedHeaderHeight, backgroundColor: 'white', borderBottomWidth: 1, borderBottomColor: '#dddddd' }}>
<View style={{
flexDirection: 'row', padding: 10,
backgroundColor: 'white', marginHorizontal: 10,
shadowOffset: { width: 0, height: 0 },
shadowColor: 'black',
shadowOpacity: 0.2,
elevation: 1,
marginTop: null
}}>
<Icon name="ios-search" size={25} style={{ marginRight: 10 ,marginTop:5 , opacity:0.6}} />
<TextInput
underlineColorAndroid="transparent"
placeholder="Find LSP"
placeholderTextColor="grey"
style={{ flex: 1, fontWeight: '700', backgroundColor: 'white' }}
/>
</View>
</Animated.View>
<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[
{ nativeEvent: { contentOffset: { y: this.scrollY } } }
]
)}
>
<View style={{ flex: 1, backgroundColor: 'white', paddingTop: 20 }}>
<Text style={styles.text}>
Laundry Service Provider Type
</Text>
<View style={{ height: 130, marginTop: 20 }}>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PlaceOrder')} activeOpacity={0.7}><Category name="Dry Clean" /></TouchableOpacity>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PlaceOrder')} activeOpacity={0.7}><Category name="Iron"/></TouchableOpacity>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PlaceOrder')} activeOpacity={0.7}><Category name="Dry Clean + Iron" /></TouchableOpacity>
</ScrollView>
</View>
<View style={{ marginTop: 40}}>
<Text style={styles.text}>
Find Nearby LSP
</Text>
<Text style={{ fontWeight: '100', marginTop: 10,paddingHorizontal: 20 }}>
Verified LSP Providers
</Text>
<View style={{ marginTop: 20, paddingHorizontal: 15
}}>
<FlatList
data={data}
renderItem={({item})=>{
return renderList(item)
}}
keyExtractor={item=>item.id}
navigation={this.props.navigation}
/>
</View>
</View>
</View>
<View style={{ marginTop: 40 }}>
<Text style={styles.text}>
Express Mode
</Text>
<View style={{ paddingHorizontal: 20, marginTop: 20, flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between' }}>
<Expressmode width={width}
name="LSP1"
type="Dry Clean"
price={82}
rating={4}
/>
<Expressmode width={width}
name="LSP2"
type="Iron + Dry Clean"
price={82}
rating={4}
/>
<Expressmode width={width}
name="LSP3"
type="Iron"
price={82}
rating={4}
/>
</View>
</View>
</ScrollView>
</View>
</SafeAreaView>
);
;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
text: {
fontSize: 24,
fontWeight:'700',
paddingHorizontal: 20
}
});
'HomeScreen.js' contains another component where I had successfully used the navigation to navigate to 'PlaceorderScreen.js'. But when I call this navigation inside Flatlist it gives the error.
NearbyLSP.js
import React from "react";
import { View, Text, StyleSheet, TouchableOpacity, Dimensions, Image } from "react-native";
import { Card } from "react-native-paper" ;
const { width } = Dimensions.get('window')
export default class NearbyLSP extends React.Component {
render() {
return (
<View>
<Card style={styles.mycard}>
<View style={{ width: width - 40, height: 200}} >
<Image
style={{ flex: 1, height: null, width: null, resizeMode: 'cover', borderRadius: 5, borderWidth: 1, borderColor: '#dddddd' }}
source={require('../assets/a.jpeg')}
/>
<Text>{this.props.name}</Text>
</View>
</Card>
</View>
);
}
}
const styles = StyleSheet.create({
mycard: {
margin: 5
}
});
App.js
import React from "react";
import { createAppContainer, createSwitchNavigator , createBottomTabNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import LoadingScreen from "./screens/LoadingScreen";
import LoginScreen from "./screens/LoginScreen";
import SignupScreen from "./screens/SignupScreen";
import HomeScreen from "./screens/HomeScreen";
import AboutScreen from "./screens/AboutScreen";
import PastorderScreen from "./screens/PastorderScreen";
import TrackScreen from "./screens/TrackScreen";
import ProfileScreen from "./screens/ProfileScreen";
import PlaceorderScreen from "./screens/PlaceorderScreen";
import MapsScreen from "./screens/MapsScreen";
import NearbyLSP from "./screens/NearbyLSP";
import { Ionicons , MaterialIcons } from '#expo/vector-icons';
import * as firebase from "firebase";
const firebaseConfig = {
apiKey: "AIzaSyAhwjD3jodBg6JGJ7Oo72r7-m2T5wwPaUg",
authDomain: "a4project-2d896.firebaseapp.com",
databaseURL: "https://a4project-2d896.firebaseio.com",
projectId: "a4project-2d896",
storageBucket: "a4project-2d896.appspot.com",
messagingSenderId: "181932238433",
appId: "1:181932238433:web:aa3f6fa3947976a8352c20",
measurementId: "G-SW6N6N8JYK"
};
firebase.initializeApp(firebaseConfig);
const HomeStack = createStackNavigator({
Home: HomeScreen,
NearbyLSP:NearbyLSP,
PlaceOrder:PlaceorderScreen
},
{
defaultNavigationOptions: {
title:'Home',
headerStyle: {
backgroundColor:'#12B2C2',
},
headerTintColor:'#fff',
headerTitleStyle:{
fontWeight:'bold'
}
}
})
const OrderStack = createStackNavigator({
Order: TrackScreen,
Maps: MapsScreen,
},
{
defaultNavigationOptions: {
title:'Orders',
headerStyle: {
backgroundColor:'#12B2C2',
},
headerTintColor:'#fff',
headerTitleStyle:{
fontWeight:'bold'
}
}
})
const PastorderStack = createStackNavigator({
Pastorder: PastorderScreen,
},
{
defaultNavigationOptions: {
title:'Pastorder',
headerStyle: {
backgroundColor:'#12B2C2',
},
headerTintColor:'#fff',
headerTitleStyle:{
fontWeight:'bold'
}
}
})
const ProfileStack = createStackNavigator({
Profile: ProfileScreen,
About: AboutScreen
},
{
defaultNavigationOptions: {
title:'Profile',
headerStyle: {
backgroundColor:'#12B2C2',
},
headerTintColor:'#fff',
headerTitleStyle:{
fontWeight:'bold'
}
}
})
const AuthStack = createStackNavigator({
Login: LoginScreen,
Signup: SignupScreen
},
{
defaultNavigationOptions: {
headerStyle: {
backgroundColor:'#12B2C2',
},
headerTintColor:'#fff',
headerTitleStyle:{
fontWeight:'bold'
}
}
})
const myTabs= createBottomTabNavigator({
Home:HomeStack,
Orders:OrderStack,
Profile:ProfileStack,
Pastorder:PastorderStack
},
{
defaultNavigationOptions: ({ navigation })=> {
return {
tabBarIcon:({tintColor})=>{
const { routeName } = navigation.state;
let myicon
if(routeName=="Home"){
myicon='md-home'
return <Ionicons name={myicon} size={30} color={tintColor}/>
}else if(routeName=="Profile"){
myicon='md-person'
return <Ionicons name={myicon} size={30} color={tintColor}/>
}else if(routeName=="Orders"){
myicon='md-book'
return <Ionicons name={myicon} size={30} color={tintColor}/>
}else if(routeName=="Pastorder"){
myicon='library-books'
return <MaterialIcons name={myicon} size={30} color={tintColor}/>
}
}
};
}
});
export default createAppContainer(
createSwitchNavigator(
{
Loading: LoadingScreen,
Auth: AuthStack,
App: myTabs
},
{
initialRouteName: "Loading"
},
)
);

Just writing navigation={this.props.navigation} in Flatlist won't let you navigate to the desired screen. You have to create a Touchable component in the Flatlist and add the navigation logic into the onPress logic of this Touchable Component.
this.props.navigation is a collection of data and methods, if you need to navigate through screens you need to use this.props.navigation.navigate('PlaceOrder')} instead, this is the method that does the navigation for you. You can console.log(this.props.navigation) to understand better.
Refer to how navigation is implemented in this answer https://stackoverflow.com/a/45407626/8851276

The code within FlatList of 'HomeScreen.js' is modified as follows
<FlatList
data={data}
renderItem={this.rendeList}
keyExtractor={item=>item.id}
/>
and the renderList function which was outside the class component is transferred inside and modified as
renderList = ({ item }) => {
return (
<TouchableOpacity
onPress={()=> this.props.navigation.navigate('PlaceOrder')}
activeOpacity={0.7}>
<NearbyLSP name={item.name}/>
</TouchableOpacity>
);
};
Due to transferring the renderList function inside the class component, it gets access to the this.props and it can be used for navigation to new screen.

Related

How to navigate from carousel slide?

I just started to learn React Native and don't understand how to make possible navigation from carousel slides. I have a carousel with 4 slides in it and I want to make it possible for a user to go to specific pages after pressing on each of these slides. For every slide, there is a different page.
I tried const navigation = useNavigation(); method, but it did not work, because a slide is not a function.
I have routes in my App.js:
export default function App () {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home"
screenOptions={{contentStyle:{backgroundColor:'#FFFFFF'}, headerTitle: (props) => <LogoTitle {...props} />, headerRight: (props) => <RightTitle {...props} /> }}>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="ItemsCategories" component={ItemsCategories} />
<Stack.Screen name="Feature1" component={Feature1} />
<Stack.Screen name="Feature2" component={Feature2} />
</Stack.Navigator>
</NavigationContainer>
);
}
Here is my code of the Carousel so far:
import React, {Component} from 'react';
import { Text, View, SafeAreaView, Image, ImageBackground, StyleSheet, Pressable, navigation } from 'react-native';
import Carousel from 'react-native-snap-carousel';
import { useNavigation } from '#react-navigation/native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
const horizontalMargin = 20;
const slideWidth = 280;
const slideHeight=470
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
flex: 1,
justifyContent: "center"
},
text: {
color: "white",
fontSize: 42,
lineHeight: 84,
fontWeight: "bold",
textAlign: "center",
textShadowColor: 'rgba(0, 0, 0, 0.75)',
textShadowOffset: {width: -1, height: 1},
textShadowRadius: 10,
width: 350
},
safe: {
position: 'absolute',
left: 0,
top: 0,
height: 360 ,
paddingTop: 10,
paddingBottom: 1
}
});
export default class HomeCarousel extends Component {
constructor(props){
super(props);
this.state = {
activeIndex:0,
carouselItems: [
{
navigate: "Feature1",
image: require('./assets/feature1.png'),
title:"Feature1",
},
{
navigate: "Feature2",
image: require('./assets/feature2.png'),
title:"Feature2",
},
{
navigate: "Feature3",
image: require('./assets/feature3.png'),
title:"Feature3",
},
{
navigate: "Feature 4",
image: require('./assets/feature4.png'),
title:"Feature 4",
},
]
}
}
_renderItem({item,index}){
return (
<Pressable onPress={()=>navigation.navigate(item.navigate)}>
<View style={{
backgroundColor:'floralwhite',
borderRadius: 5,
height: 360,
padding: 0,
marginLeft: 0,
marginRight: 0, }}>
<ImageBackground source={item.image} resizeMode="cover" style={styles.image}>
<Text style={styles.text}>{item.title}</Text>
</ImageBackground>
</View>
</Pressable>
)
}
render() {
return (
<SafeAreaView style={styles.safe}>
<View style={{ flex: 1, flexDirection:'row', justifyContent: "center" }}>
<Carousel
layout={"default"}
ref={ref => this.carousel = ref}
data={this.state.carouselItems}
sliderWidth={400}
itemWidth={400}
renderItem={this._renderItem}
onSnapToItem = { index => this.setState({activeIndex:index}) } />
</View>
</SafeAreaView>
);
}
}
If you just make HomeCarousel a functional component then you can do this below and it will work.
export default function HomeCarousel() {
const [activeIndex,setActiveIndex] = React.useState(0); // search useState online
const [carouselItems,setCarouselItems] = React.useState( [
{
navigate: "Feature1",
image: require('./assets/feature1.png'),
title:"Feature1",
},
{
navigate: "Feature2",
image: require('./assets/feature2.png'),
title:"Feature2",
},
{
navigate: "Feature3",
image: require('./assets/feature3.png'),
title:"Feature3",
},
{
navigate: "Feature 4",
image: require('./assets/feature4.png'),
title:"Feature 4",
},
]);
const ref = React.useRef(null); // search useRef online
const Item =({item,index})=> {
const navigation = useNavigation(); // Now you can use it
return (
<Pressable onPress={()=>navigation.navigate(item.navigate)}>
<View style={{
backgroundColor:'floralwhite',
borderRadius: 5,
height: 360,
padding: 0,
marginLeft: 0,
marginRight: 0, }}>
<ImageBackground source={item.image} resizeMode="cover" style={styles.image}>
<Text style={styles.text}>{item.title}</Text>
</ImageBackground>
</View>
</Pressable>
)
}
return (
<SafeAreaView style={styles.safe}>
<View style={{ flex: 1, flexDirection:'row', justifyContent: "center" }}>
<Carousel
layout={"default"}
ref={ref}
data={carouselItems}
sliderWidth={400}
itemWidth={400}
renderItem={Item}
onSnapToItem = { index =>setActiveIndex(index) } />
</View>
</SafeAreaView>
);
}

How to add DarkMode to Navigator in App.js

I have to add DarkMode switch to one of the Screen which applies to all the screen in React Native IOS App.
Below is the App.js where I wrap my main navigator inside ThemeProvider
import React from 'react';
import {Provider} from 'react-redux';
import {createStore, combineReducers,applyMiddleware} from 'redux';
import ReduxThunk from 'redux-thunk';
import authReducer from './store/reducers/auth';
import deviceReducer from './store/reducers/device';
import FR_Navigator from './navigation/FR_Navigator';
import downloadReducer from './store/reducers/download';
import { RootSiblingParent } from 'react-native-root-siblings';
import { ThemeProvider} from './theme/theme-context';
const rootReducer = combineReducers({
auth: authReducer,
download:downloadReducer,
device:deviceReducer
});
const store = createStore(rootReducer,applyMiddleware(ReduxThunk));
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<ThemeProvider>
<FR_Navigator />
</ThemeProvider>
</Provider>
);
}
}
Below is the FRNavigator which has Settings Page which sets DarkMode.
FRNavigator.js
import React from 'react';
import { View,StyleSheet,SafeAreaView,Button,ScrollView,Text} from 'react-native';
import { createSwitchNavigator,createAppContainer } from 'react-navigation';
import {createStackNavigator,StackViewTransitionConfigs} from 'react-navigation-
stack';
import MainPage from '../screens/FaceRecog/MainPage';
import UploadPage from '../screens/FaceRecog/UploadPage';
import { createDrawerNavigator,DrawerItems} from 'react-navigation-drawer';
import Icon from 'react-native-vector-icons/Ionicons';
import DownloadPage from '../screens/FaceRecog/DownloadPage';
import RateUsScreen from '../screens/FaceRecog/RateUsScreen';
import ForgotPasswordScreen from '../screens/UI/ForgotPasswordScreen';
import ImageBrowserScreen from '../screens/FaceRecog/ImageBrowserScreen';
import LoginScreen from '../screens/UI/LoginScreen';
import RegisterScreen from '../screens/UI/Register';
import AddDevicePage from '../screens/FaceRecog/AddDevicePage';
import LogoutComponent from '../components/FaceRecog/LogoutComponent'
import DrawerHeader from '../components/FaceRecog/DrawerHeader';
import CommunicateComponent from '../components/FaceRecog/CommunicateComponent';
import ManageDevice from '../screens/FaceRecog/ManageDevicePage';
import Register from '../screens/UI/Register';
import Settings from '../screens/FaceRecog/Settings';
const AuthNavigator = createStackNavigator(
{
Login:
{
screen:LoginScreen,
navigationOptions: {
headerShown: false,
}
},
SignUp:
{
screen:Register
},
ForgotPasswordPage:
{
screen:ForgotPasswordScreen,
navigationOptions: {
headerShown: true,
}
}
},
);
const MainPageNavigator = createStackNavigator({
Home:MainPage,
AddDevice:AddDevicePage,
Upload:UploadPage,
ImagePicker:ImageBrowserScreen,
ManageDev:ManageDevice,
Setting:
{
screen:Settings,
transitionConfig: () => StackViewTransitionConfigs.SlideFromRightIOS,
},
RateUs:RateUsScreen,
})
const DrawerNavigator = createDrawerNavigator(
{
Home:
{
screen:MainPageNavigator,
navigationOptions:{
drawerIcon:(
<Icon
name='md-home-sharp' size={25} color='grey'/>
)
}
},
Download:
{
screen:DownloadPage,
navigationOptions:{
drawerIcon:(
<Icon
name='md-download'
type='ionicons' size={25} color='grey'onPress={ () => {
}}/>
)
}
},
Exit:
{
screen:Register,
navigationOptions:{
drawerIcon:(
<Icon
name='exit-outline'
type='ionicons' size={25} color='grey' onPress={ () => {
}}/>
)
}
}
},
{
contentOptions:{
activeTintColor: '#e91e63',
},
contentComponent: (props) =>
<ScrollView>
<SafeAreaView style={{flex:1}} forceInset={{ top: 'always', horizontal: 'never',
height:180 }}>
<View style={{width:'100%', backgroundColor: 'white', }}>
<DrawerHeader />
</View>
<DrawerItems {...props} />
<LogoutComponent />
<View
style={{
borderBottomColor: 'grey',
borderBottomWidth: 1
}}/>
<View style={styles.communicateview}>
<Text style={styles.communicatetext}>Communicate</Text>
<CommunicateComponent {...props}/>
</View>
</SafeAreaView>
</ScrollView>,
},
);
const MainNavigator = createSwitchNavigator({
Auth: AuthNavigator,
App:DrawerNavigator
});
const styles = StyleSheet.create({
communicatetext:{
fontWeight:'800',
color:'grey'
},
communicateview:{
top:'3%',
left:'3%'
}
})
export default createAppContainer(MainNavigator);
Below is the Settings Page where I have added Toggle button to set DarkMode:
Settings.js
import React,{useState,useContext} from 'react';
import { View, StyleSheet ,Text,Switch,StatusBar,TouchableOpacity,Button} from
'react-native';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import HeaderButton from '../../components/UI/HeaderButton';
import Icon from 'react-native-vector-icons/Entypo';
import { ThemeContext } from '../../theme/theme-context';
const Settings = props => {
const { dark, theme, toggle } = useContext(ThemeContext);
return <View style={styles.container}>
<View style={styles.appsettingstextview}>
<Text style={styles.appsettingstext}>App Settings </Text>
<View style={styles.box}>
<View style={{right:80}}>
<Icon name='adjust' type='entypo' size={40} color='#00008B'/>
</View>
<View style={{right:70}}><Text style={{fontWeight:'bold'}}>Dark Mode</Text></View>
<View style={{left:80}}>
<Switch
trackColor={{ false: "#767577", true: "#ccc" }}
thumbColor={dark ? "#fff" : "#f4f3f4"}
onChange={toggle} value = {dark} />
</View>
</View>
</View>
</View>
};
const styles = StyleSheet.create({
container:{
flex:1,paddingTop:40,paddingLeft:20,
paddingBottom: 60
},
apppermissiontextview:{
},
appsettingstext:{
fontSize:17,
color:'#0437F2',
fontWeight:'bold'
},
apppermissiontextview:{
top:'5%',
},
apppermissiontext:{
fontSize:17,
color:'#0437F2',
fontWeight:'bold'
},
box: {
shadowColor: 'rgba(0,0,0, .4)', // IOS
shadowOffset: { height: 1, width: 1 },
shadowOpacity: 1, // IOS
shadowRadius: 1, //IOS
backgroundColor: '#fff',
elevation: 2, // Android
height: 80,
width:380,
borderRadius: 5,
marginVertical: 40,
backgroundColor: "#FFFFFF",
alignItems: "center",
justifyContent: "center",
flexDirection: 'row',
},
text: {
fontSize: 14,
fontWeight: "bold",
margin: 8,
color: "#000",
textAlign: "center"
}
});
Settings.navigationOptions = navData =>{
return{
headerTitle: 'Settings',
headerTitleStyle:{
color:'white',
},
headerTitleAlign:"left",
headerStyle: {
backgroundColor: '#0437F2',
},
headerLeft: () =>
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
//title="Menu"
iconName={'chevron-back-outline'}
onPress={() => {
//navData.navigation.toggleDrawer();
navData.navigation.navigate('Home');
}}
/>
</HeaderButtons>
}
};
export default Settings;
If I run the above program, when I toggle the Switch, nothing happens.Can anyone say how to add the Settings.js Page to work with FRNavigator to support darkmode toggle switch.Thanks in Advance.
I added darkmode style as style={[styles.box,{ backgroundColor: theme.backgroundColor }]}> to the View in the Settings Page and I could get switch between dark and light theme.Below is the Settings code changes I made :
Settings.js:
import React,{useState,useContext} from 'react';
import { View, StyleSheet
,Text,Switch,StatusBar,TouchableOpacity,Button} from 'react-native';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import HeaderButton from '../../components/UI/HeaderButton';
import Icon from 'react-native-vector-icons/Entypo';
import { ThemeContext } from '../../theme/theme-context';
const Settings = () => {
const { dark, theme, toggle } = useContext(ThemeContext);
return <View style={styles.container}>
<View style={styles.appsettingstextview}>
<Text style={styles.appsettingstext}>App Settings </Text>
<View style={[styles.box,{ backgroundColor: theme.backgroundColor }]}>
<View style={{right:80}}><Icon
name='adjust'
type='entypo' size={40} color='#00008B'/>
</View>
<View style={{right:70}}><Text style={[styles.darkmodetext,
{color:theme.color}]}>Dark Mode</Text></View>
<View style = {styles.containerSwitch}>
<Switch
trackColor={{ false: "#ccc", true: "#d43790" }}
thumbColor={dark ? "#f5dd4b" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
onChange={toggle} value = {dark} />
</View>
</View>
</View>
</View>
};
const styles = StyleSheet.create({
container:{
flex:1,paddingTop:40,paddingLeft:20,
paddingBottom: 60
},
appsettingstext:{
fontSize:17,
color:'#0437F2',
fontWeight:'bold'
},
darkmodetext:{
fontWeight:'bold',
fontSize:18
},
box: {
shadowColor: 'rgba(0,0,0, .4)', // IOS
shadowOffset: { height: 1, width: 1 },
shadowOpacity: 1, // IOS
shadowRadius: 1, //IOS
backgroundColor: '#fff',
elevation: 2, // Android
height: 80,
width:380,
borderRadius: 5,
marginVertical: 40,
backgroundColor: "#FFFFFF",
alignItems: "center",
justifyContent: "center",
flexDirection: 'row',
bottom:'7%'
},
text: {
fontSize: 14,
fontWeight: "bold",
margin: 8,
color: "#000",
textAlign: "center"
},
containerSwitch:{
marginBottom:50,
top:'6%',
left:'110%'
}
});
Settings.navigationOptions = navData =>{
return{
headerTitle: 'Settings',
headerTitleStyle:{
color:'white',
},
headerTitleAlign:"left",
headerStyle: {
backgroundColor: '#0437F2',
},
headerLeft: () =>
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
//title="Menu"
iconName={'chevron-back-outline'}
onPress={() => {
//navData.navigation.toggleDrawer();
navData.navigation.navigate('Home');
}}
/>
</HeaderButtons>
}
};
export default Settings;

React Navigation 4.x version issue when navigating to other screen

When Using react-navigation version 4.1.1
When navigating from one screen to another screen it is fluctuating and i am using ImageBackground there ,so first white blank screen appears after that imagebackground is loading which is very slow and i can easily see the transition over there .
I dont know what's the exact issue is there.
And for this new version i have to install libraries also for react navigation i.e.react-native screens,animated and maskedView ,safeareacontext.
So please any one know about this please let me know ..
Thanks in advance .
Here is a video for my app where i am getting image loading issue...
https://drive.google.com/open?id=16bdmxOC342uCQl3UL_hB8K0wznpbedge
Here is my APP.js File where i have created stack navigator..
import React, { Component } from 'react';
import { createAppContainer } from "react-navigation"
import { createStackNavigator } from 'react-navigation-stack';
import WelcomeScreen from './Screens/WelcomeScreen';
import Walkthorugh from './Screens/Walkthrough';
import Login from './Screens/Login';
import Signup from './Screens/Signup';
import Profile from './Screens/Profile';
import Wishlist from './Screens/Wishlish';
import Home from './Screens/Home';
import Cart from './Screens/Cart';
const notificationsel = require('./Screens/icons/notificationsel.png');
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { enableScreens } from 'react-native-screens';
import { useScreens } from 'react-native-screens';
import {
StyleSheet,
Easing,
View, Animated, FlatList,
Text, Image, Alert, YellowBox, Button, ImageBackground,
TouchableWithoutFeedback, TouchableOpacity
} from 'react-native';
const welcomeStack = createStackNavigator({
Welcome:{screen:WelcomeScreen
},
});
const homeStack = createStackNavigator({
Home:{screen:Home
},
});
const profileStack = createStackNavigator({
Profile:{screen:Profile,
navigationOptions:{header:null}},
});
const cartStack = createStackNavigator({
Cart:{screen:Cart,
navigationOptions:{header:null}},
});
const wishlistStack = createStackNavigator({
Wishlist:{screen:Wishlist,
navigationOptions:{header:null}},
});
const HomeTabNavigator = createBottomTabNavigator({
Home : homeStack,
Profile : profileStack,
Cart : cartStack,
Wishlist : wishlistStack,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation, defaultHandler }) => {
console.log('onPress:', navigation.state.routeName);
// if(navigation.state.routeName=='CallNow'){
// Linking.openURL(`tel:${'9414036555'}`)
// console.log("CallNow")
// }
defaultHandler()
},
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Home') {
iconName = focused ? notificationsel : notificationsel;
}
else if (routeName === 'Profile') {
iconName = focused ? notificationsel : notificationsel;
}
else if (routeName === 'Cart') {
iconName = focused ? notificationsel : notificationsel;
}
else if (routeName === 'Wishlist') {
iconName = focused ? notificationsel : notificationsel;
}
// You can return any component that you like here!
return <Image source={iconName} style={{width:22,height:22}}/>
;
},
}),
tabBarOptions:{
activeTintColor: 'blue',
inactiveTintColor: '#000',
showLabel:true,
style:{backgroundColor:'#fff',padding:5}
},
}
);
const AppNavigator = createStackNavigator(
{
Home: {
screen: HomeTabNavigator,
// navigationOptions:{header:null}
},
Walkthorugh:{
screen:Walkthorugh,
// navigationOptions:{header:null}
},
Welcome:{
screen:WelcomeScreen,
// navigationOptions:{header:null}
},
Login:{
screen:Login,
},
Signup:{
screen:Signup,
// navigationOptions:{header:null}
},
},
{
headerMode:'none',
initialRouteName: "Walkthorugh",
cardStyle: {backgroundColor: "transparent", opacity: 1 },
defaultNavigationOptions: {
gesturesEnabled: false,
cardStyle: {backgroundColor: "transparent", opacity: 1 },
swipeEnabled: false,
animationEnabled: false,
},
}
);
const AppContainer = createAppContainer(AppNavigator);
export default class App extends Component {
render() {
return (
<AppContainer />
)
}
}
And this is my Login.js ..
import React, { Component } from 'react';
import {
StyleSheet,
Platform,
View, ActivityIndicator, FlatList,
Text, Image, Dimensions, Keyboard, TextInput, ImageBackground,
StatusBar, TouchableOpacity
} from 'react-native';
import { NavigationActions, StackActions } from 'react-navigation';
const { width, height } = Dimensions.get('window');
const app_icon = require('./icons/app_icon.png')
const loginbg = require('./icons/loginbg.jpg')
const fashionbot = require('./icons/fashionbot.png')
import { Api_const, App_colors } from './Const/Const.js';
import { ScrollView } from 'react-native-gesture-handler';
import LinearGradient from 'react-native-linear-gradient';
export default class Login extends Component {
static navigationOptions = {
headerTitle: 'Login',
// headerLeft: (
// <View style={{ flexDirection: "row", marginLeft: 20, marginRight: 20 }}>
// <TouchableWithoutFeedback>
// <Image source={require('../assets/Hamburger.png')} >
// </Image>
// </TouchableWithoutFeedback>
// </View>
// ),
headerStyle: { borderBottomWidth: 0, marginTop: (Platform.OS === 'ios') ? 0 : 0 },
headerBackTitle: " "
};
constructor(props) {
super(props);
this.state = {
isLoading: false,
email: '',
password: '',
}
}
onClick_Login = () => {
var action = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Home',params:{test:'test'} })]
});
this.props.navigation.dispatch(action);
// setTimeout(()=>{
// this.props.navigation.dispatch(action);
// },
// 400);
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<LinearGradient colors={[App_colors.purple, App_colors.pink, App_colors.pink]} style={{flex:1}}>
<ScrollView ref="scrollView" style={{ flex:1 }} bounces={false}>
<StatusBar hidden={true} backgroundColor={App_colors.purple} barStyle="dark-content" />
<View style={{ flex:1,height}}>
<ImageBackground source={loginbg} style={{height }}>
<View style={{height }}>
<View style={{ flexDirection: 'row', margin: 15 }}>
<Image style={{ flex: 0.3, height: 90, alignItems: 'center', justifyContent: 'center', alignSelf: 'center' }} resizeMode={"contain"} source={app_icon} />
<Image style={{ flex: 1, alignItems: 'center', justifyContent: 'center', alignSelf: 'center' }} resizeMode={"contain"} source={fashionbot} />
</View>
<View style={{flex:1, justifyContent: 'center', marginLeft: 25, marginRight: 25 }}>
<Text style={{ fontSize: 22, color: '#fff', alignItems: 'center', alignSelf: 'center' }}>{'Login'}</Text>
<Text style={{ fontSize: 16, color: '#fff', marginTop: 15 }}>{'Email'}</Text>
<TextInput style={{ fontSize: 14, height: 40, marginLeft: 0, marginRight: 0, color: 'white' }}
value={this.state.email}
onChangeText={(text) => this.setState({ email: text })}
placeholder={'Your Email'}
placeholderTextColor={App_colors.white}
underlineColorAndroid={'white'}
textContentType={'username'}
keyboardType='email-address'
caretHidden={false}
onSubmitEditing={() => { Keyboard.dismiss() }}
/>
{/* PASSWORD */}
<Text style={{ fontSize: 16, color: '#fff', marginTop: 15 }}>{'Password'}</Text>
<TextInput style={{ fontSize: 14, height: 40, marginLeft: 0, marginRight: 0, color: 'white' }}
value={this.state.password}
onChangeText={(text) => this.setState({ password: text })}
placeholder={'*********'}
placeholderTextColor={App_colors.white}
underlineColorAndroid={'white'}
secureTextEntry={true}
caretHidden={false}
onSubmitEditing={() => { Keyboard.dismiss() }}
/>
<Text style={{ fontSize: 16, color: '#fff', marginTop: 5 }}>{'Forgot Password?'}</Text>
<TouchableOpacity style={{ justifyContent: 'center',alignSelf:'center', marginBottom: 10, marginTop: 30, width: width - 100, marginLeft: 0, marginRight: 0, alignItems: 'center', borderRadius: 25, borderWidth: 0, paddingTop: 15, paddingBottom: 15, backgroundColor: 'white' }}
onPress={this.onClick_Login}>
<Text style={{ fontSize: 16, color: App_colors.purple }}>{'Log in'}</Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
</View>
</ScrollView>
</LinearGradient>
);
}
}
in development mode react-native will show white screen. But in production, it won't so don't worry. it is normal.
about navigation I can't be sure but share the code or demo(image/video).

React component not re-rendering on state change using setState

I have a HomeScreen component which has button. I am trying to popup a modelview(Seperate component ie PopUpView) on the button click. In PopUpView i am sending its visibility as prop (isVisible).On the click of the button i am trying to change the state value popUpIsVisible from false to true. Hoping that this would re-render and popup my model view(Note this is working fine if i explicitly pass true). However with the state change it look like the render function is not being called and the popUp is not being displayed. Thanks for your help in advance
import React from 'react';
import { View, StyleSheet, Text, Button, TouchableHighlight, Alert, Dimensions} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import PopUpView from './src/PopUpView';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
popUpIsVisible: false,
};
}
setPopUpIsVisible(isVisible){
this.setState({popUpIsVisible: isVisible });
}
render() {
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:"blue" }}>
<Text>Home Screen</Text>
<PopUpView isVisible={this.state.popUpIsVisible}/>
<Button onPress={() => {this.setPopUpIsVisible(true)}} title="Open PopUp Screen"/>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
PopUpView.js
import React from 'react';
import { View, Modal,StyleSheet, Text, TouchableOpacity, Dimensions} from 'react-native';
import { TabView, TabBar,SceneMap } from 'react-native-tab-view';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
const FirstRoute = () => (
<View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const SecondRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
const ThirdRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
export default class PopUpView extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible:this.props.isVisible,
index: 0,
routes: [
{ key: 'first', title: 'HIGHLIGHTS' },
{ key: 'second', title: 'AMENITIES' },
{ key: 'third', title: 'FACILITIES' },
],
};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
renderHeader = props => <TabBar
{...props}
indicatorStyle={{backgroundColor: 'red'}}
tabStyle={styles.bubble}
labelStyle={styles.noLabel}
/>;
render() {
return (
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.container}>
<View style={styles.navBar}>
<Text style={styles.navBarTitle}>Test</Text>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Icon style={styles.closeButton} name="close" size={35} color="grey" />
</TouchableOpacity>
</View>
<TabView
navigationState={this.state}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
third: ThirdRoute,
})}
onIndexChange={index => this.setState({ index })}
initialLayout={{ width: Dimensions.get('window').width }}
renderTabBar={props =>
<TabBar
{...props}
style={{ backgroundColor: 'white' }}
indicatorStyle={{backgroundColor: 'black'}}
tabStyle={styles.bubble}
labelStyle={styles.label}
/>
}
/>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
margin: 50,
marginLeft: 20,
marginRight: 20,
marginBottom: 20,
backgroundColor: "white",
borderWidth: 1,
borderColor: "grey",
flexDirection: 'column'
},
navBar:{
height:70,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
borderBottomColor: 'lightgrey',
borderBottomWidth: 1,
},
navBarTitle:{
fontSize: 25,
fontFamily: 'Optima',
paddingLeft:15,
},
closeButton:{
paddingRight:12,
},
label: {
color: 'black'
}
})
The problem with your code is that you are using the state inside the PopUpView which does not change when you change the external prop. to fix this you should use the componentwillreceiveprops and update your state accordingly.
componentWillReceiveProps(nextProps){
if(this.props.isVisible!=nextProps.isVisible){
this.setState({modalVisible:nextProps.isVisible})
}
}
The better approach will be using the this.props.isVisible as the visible prop for the Model.
In this scenario you will have to pass a function as a prop to popupview which will set the popUpIsVisible to false.
Something like below
<PopUpView isVisible={this.state.popUpIsVisible}
onDismiss={()=>{this.setState({popUpIsVisible:false})}}/>
You can call the onDismiss inside the child as
<Modal visible={this.props.isVisible}>
<TouchableHighlight
onPress={() => {
this.props.onDismiss();
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</Modal>
The second approach is better as the visibility of the child is controlled by the parent.
Add below line into constructor after state defining
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);

Hide TabNavigators and Header on Scroll

I want to hide the Header and the TabNavigator tabs onScroll. How do I do that? I want to hide them onScroll and show them on ScrollUp. My code:
import React, { Component } from 'react';
import { View, Text, ScrollView, StyleSheet, TouchableOpacity} from 'react-native';
class ScrollTest extends Component {
render(){
const { params } = this.props.navigation.state;
return(
<View style={styles.container}>
<ScrollView>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
<View style={{styles.newView}}><Text>Test</Text></View>
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex:1, padding:5
},
newView:{
height: 200, backgroundColor:'green', margin:10
}
})
export default ScrollTest;
I checked this link for Animated API but not able to figureout how to implement it in onScoll?
So the header HomeScreen and the tabs Tab1 and Tab2 should hide on scroll and show when scrolled up. How do I do that?
Please help getting started on this.
Many thanks.
I was also stuck with the same animation thing, I tried this code for maximizing and minimizing the header using the Animated API of react-native.
You can also do the same for showing and hiding it.
import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView, Image,Animated } from 'react-native';
const HEADER_MAX_HEIGHT = 200;// set the initial height
const HEADER_MIN_HEIGHT = 60;// set the height on scroll
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
scrollY: new Animated.Value(0),
};
}
render() {
const headerHeight = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [HEADER_MAX_HEIGHT,HEADER_MIN_HEIGHT],
extrapolate: 'clamp',
});
return(
<View style={{flex: 1}}>
<ScrollView
scrollEventThrottle={1}
onScroll={Animated.event(
[{nativeEvent:
{contentOffset: {y: this.state.scrollY}}}]
)}>
<View style={styles.container}>
<Text style={styles.paragraph}>hello</Text>
<Image source={{uri: "https://static.pexels.com/photos/67843/splashing-splash-aqua-water-67843.jpeg"}} style={styles.imageStyle}/>
<Image source={{uri: "https://www.elastic.co/assets/bltada7771f270d08f6/enhanced-buzz-1492-1379411828-15.jpg" }}
style={styles.imageStyle}/>
</View>
</ScrollView>
<Animated.View style={[styles.footer, {height: headerHeight}]}>
<View style={styles.bar}>
<Text>text here</Text>
</View>
</Animated.View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 24,
backgroundColor: '#ecf0f1',
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
color: '#34495e',
},
imageStyle: {
height: 360,
width: '100%',
},
footer: {
position:'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: 'red',
},
bar: {
alignItems: 'center',
justifyContent: 'center',
},
});
Hope this helps someone.
I resolved for my case, hope this will be helpful
import React from 'react';
import {
Animated,
Text,
View,
StyleSheet,
ScrollView,
Dimensions,
RefreshControl,
} from 'react-native';
import Constants from 'expo-constants';
import randomColor from 'randomcolor';
const HEADER_HEIGHT = 44 + Constants.statusBarHeight;
const BOX_SIZE = Dimensions.get('window').width / 2 - 12;
const wait = (timeout: number) => {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
};
function App() {
const [refreshing, setRefreshing] = React.useState(false);
const scrollAnim = new Animated.Value(0);
const minScroll = 100;
const clampedScrollY = scrollAnim.interpolate({
inputRange: [minScroll, minScroll + 1],
outputRange: [0, 1],
extrapolateLeft: 'clamp',
});
const minusScrollY = Animated.multiply(clampedScrollY, -1);
const translateY = Animated.diffClamp(minusScrollY, -HEADER_HEIGHT, 0);
const onRefresh = React.useCallback(() => {
setRefreshing(true);
wait(2000).then(() => {
setRefreshing(false);
});
}, []);
return (
<View style={styles.container}>
<Animated.ScrollView
contentContainerStyle={styles.gallery}
scrollEventThrottle={1}
bounces={true}
showsVerticalScrollIndicator={false}
style={{
zIndex: 0,
height: '100%',
elevation: -1,
}}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollAnim } } }],
{ useNativeDriver: true }
)}
overScrollMode="never"
contentInset={{ top: HEADER_HEIGHT }}
contentOffset={{ y: -HEADER_HEIGHT }}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}>
{Array.from({ length: 20 }, (_, i) => i).map((uri) => (
<View style={[styles.box, { backgroundColor: 'grey' }]} />
))}
</Animated.ScrollView>
<Animated.View style={[styles.header, { transform: [{ translateY }] }]}>
<Text style={styles.title}>Header</Text>
</Animated.View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
gallery: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: 4,
},
box: {
height: BOX_SIZE,
width: BOX_SIZE,
margin: 4,
},
header: {
flex: 1,
height: HEADER_HEIGHT,
paddingTop: Constants.statusBarHeight,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
right: 0,
backgroundColor: randomColor(),
},
title: {
fontSize: 16,
},
});
export default App;
checkout on Expo https://snack.expo.io/#raksa/auto-hiding-header