React Native Custom Drawer Navigation (navigation.closeDrawer()) - reactjs

I'm new to react native i've been trying to create a custom drawer. Inside i wanted to add a button that would close the drawer however i've been getting the error TypeError: undefined is not an object (evaluating 'navigation.closeDrawer') this is my code:
import React, { useState } from "react";
import {DrawerActions} from '#react-navigation/native';
import Logo from '../assets/images/Logo.png'
import {
View,
Text,
Image,
TouchableOpacity,
ScrollView
} from 'react-native';
import {
createDrawerNavigator,
DrawerContentScrollView,
} from '#react-navigation/drawer';
import { MainLayout } from "../screens";
import {
COLORS,
FONTS,
SIZES,
constants,
icons,
dummyData,
} from '../constants';
import Animated from "react-native-reanimated";
const Drawer = createDrawerNavigator()
const CustomDrawerItem = ({label, icon}) => {
return (
<TouchableOpacity
style={{
flexDirection: 'row',
height: 40,
marginBottom: SIZES.base,
alignItems: 'center',
paddingLeft: SIZES.radius,
borderRadius: SIZES.base
}}
>
<Image
source={icon}
style={{
width: 20,
height: 20,
tintColor: COLORS.primary
}}/>
<Text
style={{
marginLeft: 15,
color: COLORS.primary,
...FONTS.h3
}}
>
{label}
</Text>
</TouchableOpacity>
)
}
const CustomDrawerContent = ({ navigation }) => {
return (
<DrawerContentScrollView
scrollEnbled={true}
contentContainerStyle={{ flex: 1}}
>
<ScrollView
style={{
flex: 1,
paddingHorizontal: SIZES.radius
}}
>
{/* Logo*/}
<TouchableOpacity
style = {{
flexDirection: 'row',
marginTop: SIZES.radius,
alignItems: 'center',
marginBottom: 20,
}}>
<Image style={{
flex: 1,
width: 80,
height: 80,
resizeMode: 'contain',
marginLeft: -60,
}}
source={Logo}/>
<View
style={{
marginLeft: SIZES.radius
}}
>
<View
style={{
alignItems: 'flex-end',
justifyContent: 'center'
}}
>
<TouchableOpacity
style={{
alignItems: 'center',
justifyContent: 'center',
tintColor: COLORS.black
}}
onPress={() => navigation.closeDrawer()}
>
<Image
source={icons.cross}
style={{
height: 25,
width: 25,
}}
/>
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
{/* Profile */}
<TouchableOpacity
style = {{
flexDirection: 'row',
marginTop: SIZES.radius,
alignItems: 'center'
}}>
<View
style={{
marginLeft: SIZES.radius
}}
>
<CustomDrawerItem
icon={icons.profile}
label={constants.sideBarElements.guest}
/>
<View>
{dummyData.GuestData.map(
(item, index) => (
<Text
style={{
paddingLeft: 20,
paddingTop: 10,
color: COLORS.gray
}}>
{item.name}
</Text>
)
)}
</View>
</View>
</TouchableOpacity>
{/* Line devider
<View
style={{
height: 1,
marginVertical: SIZES.radius,
//marginLeft: SIZES.radius,
backgroundColor: COLORS.lightGray1
}}
/>*/}
{/* Drawer Items */}
<View
style={{
flex: 1,
marginTop: SIZES.padding,
marginLeft: SIZES.radius
}}
>
<CustomDrawerItem
icon={icons.cart}
label={constants.sideBarElements.store}
/>
<View>
{dummyData.storesData.map(
(item, index) => (
<Text
style={{
paddingLeft: 20,
paddingTop: 10,
color: COLORS.gray
}}>
{item.title}
</Text>
)
)}
</View>
</View>
<View
style={{
flex: 1,
marginTop: SIZES.padding,
marginLeft: SIZES.radius,
marginBottom: 50
}}
>
<CustomDrawerItem
icon={icons.cart}
label={constants.sideBarElements.categories}
/>
<View>
{dummyData.carouselData.map(
(item, index) => (
<Text
style={{
paddingLeft: 20,
paddingTop: 10,
color: COLORS.gray
}}>
{item.category}
</Text>
)
)}
</View>
</View>
</ScrollView>
</DrawerContentScrollView>
)
}
const CustomDrawer = () => {
const [progress, setProgress] = useState(new Animated.Value(0))
const scale = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [1, 0.8]
})
const borderRadius = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [0, 26]
})
const animatedStyles = {borderRadius, transform: [{scale}]}
return (
<View
style={{
flex: 1,
backgroundColor: COLORS.primary
}}
>
<Drawer.Navigator
drawerType='slide'
overlayColor='transparent'
drawerStyle={{
flex: 1,
width: '65%',
paddingRight: 20,
backgroundColor: 'transparent'
}}
sceneContainerStyle={{
backgroundColor: 'transparent'
}}
initialRouteName='MainLayout'
drawerContent={props => {
setTimeout(()=> {
setProgress(props.progress)
}, 0)
return (
<CustomDrawerContent
navigration ={props.navigation}
/>
)
}}
>
<Drawer.Screen name='MainLayout'>
{props => <MainLayout {...props} drawerAnimationStyle={animatedStyles}/>}
</Drawer.Screen>
</Drawer.Navigator>
</View>
)
}
export default CustomDrawer;
i even tried it with dispatch but i get the same error i'm not sure what i'm doing wrong.

Try this
import {useNavigation} from '#react-navigation/native';
const navigation = useNavigation();
navigation.openDrawer();
navigation.closeDrawer();

Related

how to set modal visible according to id?

I have a map() data each of which has touchableopacity that should set the state of modal visible to true, but am unable to do it.
Could anyone let me know a way to set the state according to id?
ParentComponent:
export default function ExpandedVaccineComponent(props) {
const {navigation} = props;
const [note, setNote] = useState({});
const [addNoteText, setAddNoteText] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [selectedItem,setSelectedItem]=useState(null);
const [demo, setDemo] = useState(false);
let id = props.id;
return (
<View
style={{
backgroundColor: '#fff',
elevation: 3,
margin: '2%',
borderRadius: 5,
}}>
<View style={{marginTop: '2%'}}>
{props.item.vaccine_list.map((i) => {
return (
<View style={{flex: 1}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={() => setModalVisible(true)}>
<Icon name="calendar" size={15} />
</TouchableOpacity>
<View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}>
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
}}>
<CalenderModal
item={props.item}
modalVisible={modalVisible}
item={i}
id={id}
/>
<View
style={{
flexDirection: 'row',
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
width: '72%',
}}>
<TouchableOpacity
style={{
flex: 1,
borderTopColor: '#C0C0C0',
borderTopWidth: 1,
borderRightColor: '#C0C0C0',
borderRightWidth: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 10,
}}
onPress={() => setModalVisible(!modalVisible)}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
fontWeight: 'bold',
color: '#2D7AFA',
}}>
Cancel
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
borderTopColor: '#C0C0C0',
borderTopWidth: 1,
borderLeftColor: '#C0C0C0',
borderLeftWidth: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 10,
}}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
fontWeight: 'bold',
color: '#2D7AFA',
}}>
Save
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
<View style={{marginLeft: '10%', width: '30%'}}>
<View>
<View style={{flexDirection: 'row'}}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 14,
color: '#000',
}}>
{i.name}
</Text>
<Text
style={{
fontFamily: 'Roboto',
color: '#000',
opacity: 0.5,
}}>
(Dose{i.dose}/3)
</Text>
</View>
<Text
numberOfLines={2}
ellipsizeMode="tail"
style={{
fontFamily: 'Roboto',
fontSize: 14,
lineHeight: 14,
color: '#000',
opacity: 0.5,
}}>
{i.protects_against}
</Text>
</View>
</View>
<View style={{marginLeft: '30%'}}>
<Text>{i.child_vacc_status.text}</Text>
<Text>16 Aug,2020</Text>
</View>
</View>
</View>
);
})}
</View>
</View>
);
}
CalenderModal component:
import React, {useState} from 'react';
import {View, Text, StyleSheet, TouchableOpacity, Image} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import DatePicker from 'react-native-datepicker';
import axios from 'axios';
import {ROOT} from '../../../ApiUrl';
export default function CalenderModal(props) {
const [date, setDate] = useState('2016-05-15');
const [vaccinatedOn, setVaccinatedOn] = useState(null);
const [reminder, setReminder] = useState(1);
const [toggle, setToggle] = useState(null);
const [modalVisible, setModalVisible] = useState(null);
const reminderSet = () => {
setReminder(6);
setToggle(6);
};
const vaccinationSet = () => {
setVaccinatedOn(1);
setToggle(1);
};
const data = props.item;
const id = props.id;
const SaveData = () => {
let url = `some url`;
axios({
method: 'POST',
url: url,
data: {
child_id: id,
event_date: date,
status: toggle,
vaccine_id: data.id,
},
headers: {
'content-type': 'application/json',
},
})
.then(function (res) {
console.log('RES', res);
if (res.data.code == 200) {
navigation.navigate('consultationHome', {res: res});
}
})
.catch(function (err) {
console.log('ERR', err);
});
};
return (
<View>
<View style={styles.modalView}>
<Text>{props.item.name}</Text>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: '5%',
}}>
{reminder == 6 && toggle == 6 ? (
<TouchableOpacity style={{flexDirection: 'row'}}>
<Icon
name="circle"
size={17}
color="pink"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Set reminder
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => reminderSet()}>
<Icon
name="circle-o"
size={17}
color="#000"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Set reminder
</Text>
</TouchableOpacity>
)}
{vaccinatedOn == 1 && toggle == 1 ? (
<TouchableOpacity style={{flexDirection: 'row'}}>
<Icon
name="circle"
size={17}
color="pink"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Vaccinated on
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => vaccinationSet()}>
<Icon
name="circle-o"
size={17}
color="#000"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Vaccinated on
</Text>
</TouchableOpacity>
)}
</View>
<DatePicker
style={{width: 200, marginTop: '5%'}}
date={date}
mode="date"
placeholder="select date"
format="YYYY-MM-DD"
minDate="2016-05-01"
maxDate="2016-06-01"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
customStyles={{
dateIcon: {
position: 'absolute',
left: 0,
top: 4,
marginLeft: 0,
},
dateInput: {
marginLeft: 36,
},
// ... You can check the source to find the other keys.
}}
onDateChange={(date) => {
setDate(date);
}}
/>
{console.log('DATE', date)}
</View>
</View>
);
}
const styles = StyleSheet.create({
modalView: {
backgroundColor: 'white',
padding: 20,
},
});
Any suggestion would be great, please let me know if anything else is required for better understanding.
you might want to try setting up your onPress similar to the RN documentation for TouchableOpacity (https://reactnative.dev/docs/touchableopacity.html you also may want to consider switching to Pressable for future proofing purposes). You can do
const onPress = () => setModalVisible(true);
<TouchableOpacity onPress={onPress}>

How to append new images to the array using react native image crop picker?

Hi, I am using react-native-image-crop-picker to overcome the above-shown module to select images from the gallery and display it in react native app, but I also want to click on add photo and again select images from the gallery and append them to the previous array of photos, am unable to figure that out.
This is the exact code that I have written to achieve the above-shown behavior, what should I change or add to perform the append feature?
import React, {useEffect, useState} from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
Image,
TouchableOpacity,
Dimensions,
FlatList,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import ImagePicker from 'react-native-image-crop-picker';
const deviceWidth = Dimensions.get('window').width;
const deviceHeight = Dimensions.get('window').height;
const App = () => {
const [photos, setAddPhotos] = useState(null);
const [photo, setAddphoto] = useState(null);
const handleChoosePhoto = () => {
ImagePicker.openPicker({
multiple: true,
waitAnimationEnd: false,
includeExif: true,
forceJpg: true,
})
.then((images) => {
setAddphoto(null);
setAddPhotos(
images.map((i) => {
console.log('recieved image', i);
return {
uri: i.path,
// width: i.width,
// height: i.height,
width: 185,
height: 128,
mime: i.mime,
};
}),
);
})
.catch((e) => alert(e));
};
const renderImage = (image) => {
return (
<Image
style={{
width: 185,
height: 128,
resizeMode: 'contain',
marginTop: 1,
}}
source={image}
/>
);
};
const renderAsset = (image) => {
return renderImage(image);
};
return (
<View style={{flex: 1}}>
{console.log('PHOTOS', photos)}
{photos === null ? (
<View style={{flex: 1}}>
<View style={Styles.headerWrapper}>
<View
style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Icon name="angle-left" size={30} />
<TouchableOpacity style={{right: '10%', top: '2%'}}>
<Text style={{fontSize: 15, fontWeight: 'bold'}}>
SAVE AND EXIT
</Text>
</TouchableOpacity>
</View>
</View>
<ScrollView>
<Text style={Styles.headerText}>Add photos to your listing</Text>
<Text style={Styles.subHeader}>
Photos help guests imagine staying in your place. You can start
with one and add more after you publish.
</Text>
<View style={Styles.container}>
<TouchableOpacity onPress={() => handleChoosePhoto()}>
<View
style={{
backgroundColor: '#20B2AA',
width: 150,
height: 40,
borderRadius: 5,
justifyContent: 'center',
}}>
<Text
style={{
color: '#fff',
textAlign: 'center',
fontSize: 15,
fontWeight: 'bold',
}}>
Add photos
</Text>
</View>
</TouchableOpacity>
</View>
</ScrollView>
<TouchableOpacity
style={{
alignSelf: 'flex-end',
right: '5%',
position: 'absolute',
bottom: 10,
}}>
<View
style={{
borderColor: '#20B2AA',
borderWidth: 1,
alignSelf: 'flex-end',
padding: 10,
}}>
<Text
style={{fontSize: 15, fontWeight: 'bold', color: '#20B2AA'}}>
Skip For Now
</Text>
</View>
</TouchableOpacity>
</View>
) : (
<>
<View style={{flex: 1}}>
<View style={Styles.headerWrapper}>
<View
style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<Icon name="angle-left" size={30} />
<TouchableOpacity style={{right: '10%', top: '2%'}}>
<Text style={{fontSize: 15, fontWeight: 'bold'}}>
SAVE AND EXIT
</Text>
</TouchableOpacity>
</View>
</View>
<ScrollView>
<View style={{flex: 1, flexWrap: 'wrap', flexDirection: 'row'}}>
{photos
? photos.map((i) => (
<View
style={{
// width: 185, height: 128,
// width:'50%',
flexBasis: '33.33%',
}}
key={i.uri}>
{renderAsset(i)}
</View>
))
: null}
</View>
</ScrollView>
<TouchableOpacity
style={{
alignSelf: 'flex-end',
right: '5%',
position: 'absolute',
bottom: 10,
}}>
<View
style={{
backgroundColor: '#20B2AA',
alignSelf: 'flex-end',
padding: 10,
}}>
<Text style={{fontSize: 15, fontWeight: 'bold', color: '#FFF'}}>
NEXT
</Text>
</View>
</TouchableOpacity>
</View>
</>
)}
</View>
);
};
export default App;
const Styles = StyleSheet.create({
headerWrapper: {
width: deviceWidth,
paddingLeft: 24,
paddingTop: 10,
paddingBottom: 10,
},
headerText: {
fontWeight: 'bold',
fontSize: 28,
paddingLeft: 24,
},
container: {
padding: 24,
},
subHeader: {
paddingLeft: 24,
fontSize: 17,
paddingTop: 24,
paddingRight: 24,
},
});
Please let me know if anything else is required for better understanding, thank you.
You only need to take the prevState in setAddPhotos
setAddPhotos((lastPhotos) => {
const imagesMap = images.map((i) => {
return {
uri: i.path,
width: i.width,
height: i.height,
mime: i.mime,
};
});
return [...lastPhotos, ...imagesMap];
});

Display a Modal on a holding modal on react native

I was trying to display a modal on another model its visibility always set to true. I tried multiple ways but still I am unable to show that modal. I am printing here the code to make it a sense:
function Search({navigation}) {
const [number, setNumber] = useState('');
const [visible, setvisible] = useState(false);
return (
<View style={{flex: 1, backgroundColor: 'rgba(0,0,0,0.5)'}}>
<Modal
visible={true}
transparent={true}
style={{
elevation: 24,
borderRadius: 24,
marginTop: 60,
backgroundColor: '#fafcff',
}}>
<View
style={{
margin: 50,
padding: 10,
borderRadius: 35,
height: 40,
flexDirection: 'column',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 12,
},
shadowOpacity: 0.58,
shadowRadius: 16.0,
elevation: 24,
}}>
<TextInput
label="Enter a phone number"
value={textInput}
keyboardType="numeric"
maxLength={12}
mode="outlined"
dense={true}
// ref={textInput.current.clear()}
theme={{
colors: {
primary: '#00aaff',
},
}}
onChangeText={(text) => {
setNumber(text);
}}
/>
<Button
mode="contained"
theme={{
colors: {
primary: '#006aff',
},
}}
style={{
margin: 70,
marginTop: 10,
padding: 2,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.34,
shadowRadius: 6.27,
justifyContent: 'center',
elevation: 18,
borderRadius: 18,
textAlign: 'center',
}}
onPress={() => {
if (number === '') {
<Modal visible={!visible} transparent={true} animationType={'fade'}>
<View style={styles.mainOuterComponent}>
<View style={styles.mainContainer}>
{/* First ROw - Alert Icon and Title */}
<View style={styles.topPart}>
{true && (
<Image
source={require('../images/ic_notification.png')}
resizeMode={'contain'}
style={styles.alertIconStyle}
/>
)}
<Text style={styles.alertTitleTextStyle}>
{/* {`${alertTitleText}`} */} Here worked
</Text>
</View>
{/* Second Row - Alert Message Text */}
<View style={styles.middlePart}>
<Text style={styles.alertMessageTextStyle}>
{/* {`${alertMessageText}`} */} EMpty value
</Text>
</View>
{/* Third Row - Positive and Negative Button */}
<View style={styles.bottomPart}>
{true && (
<TouchableOpacity
// onPress={this.onPositiveButtonPress}
style={styles.alertMessageButtonStyle}>
<Text style={styles.alertMessageButtonTextStyle}>
{/* {positiveButtonText} */} Okay
</Text>
</TouchableOpacity>
)}
</View>
</View>
</View>
</Modal>
} else {
console.log('Do Nothing!');
}
}}>
<Text
style={{
fontSize: 25,
color: 'white',
textAlign: 'center',
}}>
{' '}
<MaterialCommunityIcons
name="database-search"
size={40}
color="yellow"
style={{
paddingRight: 5,
alignItems: 'center',
margin: 5,
}}></MaterialCommunityIcons>
Search
</Text>
</Button>
</Modal>
</View>
)
}
expected that when user clicks "search" while the input is empty, a modal showing empty value entered. I got nothing, no error. How can I solve this?
Make two components, then render it based on conditions inside one modal, I used this way for many components.
const ModalContent = ({toggleModal}) => {
const [defaultContent, setDefaultContent] = useState(true);
const conditionalRendering = ()=> {
if(defaultContent === true) return (
<View>
<TouchableOpacity onPress={()=> setDefaultContent(false)}>
<Text>First Content</Text>
</TouchableOpacity>
</View>
);
return (
<View>
<TouchableOpacity onPress={()=> setDefaultContent(true)}>
<Text>Second Content</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={{flex:1, justifyContent: 'center', alignItems: 'center'}}>
{conditionalRendering()}
</View>
);
}
<Modal
useNativeDriver
onBackButtonPress={toggleModal}
isVisible={modalVisible}
style={{ padding: 0, margin: 0, justifyContent: 'center' }}
>
<ModalContent toggleModal={toggleModal} />
</Modal>

Getting a navigation.navigate type error after spliting the mainscreen into components

I was working on my app with two screens a Main Screen and a Details Screen everything was working, but the code was long, so I tried to split everything into reusable components which caused a
navigation.navigates type error for some reason.
I checked the code multiple times everything makes perfect sense to me is there something am missing here, how do I fixed this error?
Am using react navigation version 5 for the first time.
Here is a sample of the code used:
MainScreen.js
import React from "react";
import { StyleSheet, Text, View, Image, FlatList } from "react-native";
import ArticleList from "../components/ArticleList";
function MainScreen() {
return (
<View style={{ flex: 1 }}>
{/* show the data in a flatlist */}
<ArticleList />
</View>
);
}
MainScreen.navigationOptions = () => {
return {
headerShown: false,
};
};
export default MainScreen;
DetailScreen.js
import React from "react";
import { StyleSheet, Text, View, Dimensions, Image } from "react-native";
import { Feather } from "#expo/vector-icons";
import { SharedElement } from "react-native-shared-element";
import { TouchableOpacity, ScrollView } from "react-native-gesture-handler";
const DetailScreen = (props) => {
const { width, height } = Dimensions.get("window");
const { data } = props.route.params;
return (
<View style={styles.container}>
<View>
<SharedElement id={`item.${data.id}.photo`}>
<Image
resizeMode="cover"
source={{ uri: data.image }}
style={{
width: 400,
height: 300,
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
}}
/>
</SharedElement>
<View
style={{
flexDirection: "row",
alignItems: "center",
position: "absolute",
bottom: 14,
left: 10,
}}
>
<SharedElement id={`item.${data.id}.profilePic`}>
<Image
resizeMode="cover"
source={{ uri: data.profilePic }}
style={{
width: 60,
height: 60,
borderRadius: 10,
marginRight: 14,
}}
/>
</SharedElement>
<View
style={{
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<View>
<SharedElement id={`item.${data.id}.username`}>
<Text
style={{ color: "white", fontSize: 16, fontWeight: "bold" }}
>
{data.username}
</Text>
</SharedElement>
<SharedElement id={`item.${data.id}.readtime`}>
<Text style={{ color: "white", fontSize: 14 }}>
{data.readtime}
</Text>
</SharedElement>
</View>
<TouchableOpacity>
<Feather name="bookmark" size={30} color="white" />
</TouchableOpacity>
</View>
</View>
</View>
<ScrollView style={{ paddingHorizontal: 10, paddingTop: 14 }}>
<SharedElement
id={`item.${data.id}.text`}
style={{ width: width - 30, marginBottom: 14 }}
>
<Text style={{ fontSize: 22, fontWeight: "bold", lineHeight: 32 }}>
{data.title}
</Text>
</SharedElement>
<Text
style={{
fontSize: 14,
lineHeight: 28,
textAlign: "justify",
opacity: 0.5,
}}
>
Paragraph 1
</Text>
<Text
style={{
fontSize: 14,
lineHeight: 28,
textAlign: "justify",
opacity: 0.5,
}}
>
Paragraph 2
</Text>
<View
style={{
marginVertical: 25,
paddingBottom: 20,
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<TouchableOpacity
style={{ flexDirection: "row", padding: 12, alignItems: "center" }}
>
<Feather name="heart" size={16} color="orange" />
<Text style={{ marginHorizontal: 10 }}>3.4k Likes</Text>
</TouchableOpacity>
</View>
</ScrollView>
<View style={{ position: "absolute", top: 40, left: 10 }}>
<TouchableOpacity onPress={() => props.navigation.goBack()}>
<Feather name="arrow-left" size={24} color="white" />
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
export default DetailScreen;
ArticleList.js
import React from "react";
import {
View,
Text,
StyleSheet,
Image,
Dimensions,
FlatList,
} from "react-native";
import { SharedElement } from "react-native-shared-element";
import TouchableScale from "react-native-touchable-scale";
import { data } from "../data";
function ArticleList({ navigation }) {
const { width, height } = Dimensions.get("window");
return (
<View>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
style={{ paddingHorizontal: 30 }}
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item }) => {
return (
<View>
<View>
<TouchableScale
activeScale={0.9}
tension={50}
friction={7}
useNativeDriver
onPress={() =>
navigation.navigate("DetailScreen", { data: item })
}
>
{/* to show the horizental news list*/}
<SharedElement id={`item.${item.id}.photo`}>
<Image
source={{ uri: item.image }}
style={{
width: width - 100,
height: height - 350,
borderRadius: 14,
marginRight: 30,
}}
/>
</SharedElement>
{/* to show the news titles inside the pictures*/}
<SharedElement
id={`item.${item.id}.text`}
style={{
width: width - 100,
position: "absolute",
bottom: 90,
left: 10,
paddingHorizontal: 10,
}}
>
<Text style={styles.blogTitle}>{item.title}</Text>
</SharedElement>
{/* to show the pictre of the author of the news article*/}
<View
style={{
flexDirection: "row",
alignItems: "center",
position: "absolute",
bottom: 20,
left: 20,
}}
>
<SharedElement id={`item.${item.id}.profilePic`}>
<Image
resizeMode="cover"
source={{ uri: item.profilePic }}
style={styles.blogProfilePic}
/>
</SharedElement>
</View>
{/* to show the name of the author and read time of article*/}
<View>
<SharedElement id={`item.${item.id}.username`}>
<Text style={styles.blogUsername}>{item.username}</Text>
</SharedElement>
<SharedElement id={`item.${item.id}.readtime`}>
<Text style={styles.readtime}>{item.readtime}</Text>
</SharedElement>
</View>
</TouchableScale>
</View>
</View>
);
}}
/>
</View>
);
}
const styles = StyleSheet.create({
blogTitle: {
color: "white",
fontSize: 24,
fontWeight: "bold",
lineHeight: 28,
},
blogProfilePic: {
height: 50,
width: 50,
borderRadius: 10,
marginRight: 14,
},
blogUsername: {
color: "white",
fontSize: 16,
fontWeight: "bold",
},
readtime: {
fontSize: 14,
color: "white",
},
});
export default ArticleList;
App.js
import React from "react";
import "react-native-gesture-handler";
import { createSharedElementStackNavigator } from "react-navigation-shared-element";
import { NavigationContainer } from "#react-navigation/native";
import MainScreen from "./app/screens/MainScreen";
import DetailScreen from "./app/screens/DetailScreen";
const Stack = createSharedElementStackNavigator();
const App = ({ navigation }) => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="MainScreen"
screenOptions={{ headerShown: false }}
>
<Stack.Screen name="MainScreen" component={MainScreen} />
<Stack.Screen
name="DetailScreen"
component={DetailScreen}
options={(navigation) => ({
headerBackTitleVisible: false,
cardStyleInterpolator: ({ current: { progress } }) => {
return {
cardStyle: {
opacity: progress,
},
};
},
})}
sharedElements={(route) => {
const { data } = route.params;
return [
{
id: `item.${data.id}.photo`,
animation: "move",
resize: "clip",
align: "center-top",
},
{
id: `item.${data.id}.text`,
animation: "fade",
resize: "clip",
align: "left-center",
},
{
id: `item.${data.id}.profilePic`,
animation: "move",
resize: "clip",
align: "left-center",
},
{
id: `item.${data.id}.username`,
animation: "fade",
resize: "clip",
align: "left-center",
},
{
id: `item.${data.id}.readtime`,
animation: "fade",
resize: "clip",
align: "left-center",
},
];
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
My apologies for the long samples of code I tried to keep everything that is connected directly to the problem.
The problem is the you are accessing navigation outside the navigation stack. When you moved the flatlist to to ArticleList its outside the navigation and it wont get the navigation prop.
You can handle this in two ways.
You can simply pass the navigation from the main screen
function MainScreen({ navigation }) {
return (
{/* show the data in a flatlist */}
< ArticleList navigation={navigation} />
);
}
You can use the useNavigation hook to access navigation outside navigation.

Dynamically set values to variables in React/React Native .map function

I want to dynamically set the value to variables in .map function but it appears to syntax errors. Please help me out.
I used to use {} to wrap the JavaScript code in html but this time it didn't work as expected.
Additionally I also wondering that is it possible to access variables stored in the local state object within .map function.
import React from 'react';
import { View, Text } from 'react-native';
import { Icon, Avatar } from 'react-native-elements';
class SearchListItem extends React.Component {
render() {
const { id, title, shortDescription, time, locationDescription, peopleGroup } = this.props.item;
const indexX = -28;
const indexZ = 1.1;
return (
<View style={styles.containerStyle}>
<View style={{ flexDirection: 'row' }}>
<View style={{ width: '90%' }}>
<Text style={styles.title}>{title}</Text>
</View>
<View style={{ width: '10%' }}>
<Icon
name='star-outline'
type='material-community'
color='#666666' />
</View>
</View>
<View>
<Text style={{ marginTop: 5, color: '#666666' }}>{shortDescription}</Text>
<Text style={{ marginTop: 5 }}>{time}</Text>
<Text style={{ marginTop: 5 }}>{locationDescription}</Text>
</View>
<View style={{ flexDirection: 'row', marginTop: 20 }}>
{const i = 0}
peopleGroup.map((people) => (
<Avatar
width={30}
position='absolute'
containerStyle={{ transform: [{translate: [-28 + (28 * i), 0, 20]}] }}
small
rounded
source={{uri: "http://www.5seestar.com/jiaoxuewen/images/1701/dengchao.jpg"}}
activeOpacity={0.7}
/> ));
</View>
</View>
);
}
};
const styles = {
containerStyle: {
padding: 30,
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'center',
marginTop: 5
},
title: {
fontWeight: 'bold',
fontSize: 18
}
};
export default SearchListItem;
All you want to do is to use the index of the mapped value, so you can use this i guess :
<View style={{ flexDirection: 'row', marginTop: 20 }}>
{
peopleGroup.map((people,i) => (
<Avatar
width={30}
position='absolute'
containerStyle={{ transform: [{translate: [-28 + (28 * i), 0, 20]}] }}
small
rounded
source={{uri:"http://www.5seestar.com/jiaoxuewen/images/1701/dengchao.jpg"}}
activeOpacity={0.7}
/>
));
}
</View>

Resources