React navigation: navigate from screen to another screen showing previous data - react-native

I'm developing a food ordering app using react native and ASP .NET MVC Entity Framework.
I've Search screen with date(field) and vendor list(dropdown) and when I click on search button it will navigate to Orders Screen with date and vendor Id as parameters and with these 2 parameter I fetch data from API and show data with in Orders screen. But problem is first time it's showing correct list and 2nd time with different date and vendor id not updating list in Orders screen while API fetching correct data and showing previous data.
Search Screen Code
<View style={[styles.container, { backgroundColor: colors.background }]}>
<StatusBar style={theme.dark ? "light" : "dark"} />
<CustomLoading isLoading={isLoading} />
{/* Header */}
<View style={styles.header}>
<Animatable.View animation="bounceIn" duration={2000}>
<Image style={styles.logo} source={images.FinalLogoOnLight} />
</Animatable.View>
<Animatable.Text
animation="bounceInLeft"
duration={2000}
style={[styles.screenTitle, { color: colors.black }]}
>
Search/Filter Receipts
</Animatable.Text>
</View>
{/* Form */}
<View>
{/* Date */}
<TouchableOpacity
style={[styles.datePickerWrapper, { backgroundColor: colors.white }]}
onPress={showDatePicker}
>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
value={model.date}
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
<Text style={{ color: colors.black, fontFamily: "PoppinsRegular" }}>
{moment(model.date).format("YYYY-MM-DD")}
</Text>
<AntDesign name="calendar" color={colors.gray} size={sizes.h2} />
</TouchableOpacity>
{/* DropDown */}
{/* <FormDropDown dropDownRef={dropDownRef} options={vendors} /> */}
<View
style={[
styles.dropDownWrapper,
{
flexDirection: "row",
marginTop: sizes.m10,
justifyContent: "center",
alignItems: "center",
backgroundColor: colors.white,
borderColor: colors.grayLight,
},
]}
>
{model.vendors != null ? (
<FormPicker
placeholderText="Select Vendor"
selectedValue={model.vendorUserId}
onValueChange={(val) => setModel({ ...model, vendorUserId: val })}
data={model.vendors}
/>
) : null}
</View>
{/* Search Button */}
<FormButton
mystyle={{ marginTop: sizes.m20 }}
buttonTitle="Search"
onPress={() => handleSubmit()}
/>
</View>
const handleSubmit = async () => {
try {
if (model.vendorUserId == "" && model.date == "") {
Toast.show("Date or Vendor filed not be empty.");
return;
}
navigation.navigate("RootOrder", {
screen: "SearchedOrders",
params: { searchedOrders: model },
});
} catch (error) {
console.log(error);
setIsLoading(false);
}
};
Searched Order Screen
const [isLoading, setIsLoading] = useState(true);
const [start, setStart] = useState(0);
const [model, setModel] = useState({
data: [],
token: userState.token,
date: searchedOrders.date,
vendorUserId: searchedOrders.vendorUserId,
recordTotal: null,
});
// Functions
const fetchOrderHistoryByDate = async () => {
try {
setIsLoading(true);
var res = await orderHistoryByDate(model);
if (!res.Success) {
console.log("Error: ", res.Data);
setIsLoading(false);
alert(res.Data);
return;
}
var resModel = res.Data;
// console.log(resModel)
setModel({ ...model, data: resModel });
// console.log(resModel);
setIsLoading(false);
} catch (error) {
console.log(error);
setIsLoading(false);
}
};
// Functions END
const init = async () => {
await fetchOrderHistoryByDate();
setIsLoading(false);
};
useEffect(() => {
const unsubscribe = navigation.addListener("focus", () => {
setStart(Math.random() * 10000);
init();
});
return unsubscribe;
}, [start]);
function renderCardItems({ item, index }) {
return (<View style={styles.OrderItemWrapper}>
<LinearGradient
style={[styles.OrderItemWrapperLinearGrad]}
colors={[colors.white, colors.linearGray]}
>
<TouchableOpacity
// style={[styles.OrderItemWrapper, { backgroundColor: colors.white }]}
onPress={() =>
navigation.navigate("OrderDetails", { itemOrderDetails: item })
}
// key={index}
>
<View style={styles.cartItemWrapper}>
<View style={styles.cartItemDetails}>
<Text style={[styles.cartItemText, { color: colors.primary }]}>
{item.ShopName}
{/* ({index}) */}
</Text>
{/* <Text style={{ color: "#000" }}>{item.InvoiceNo}</Text> */}
<Text
style={[styles.cartItemQuantityText, { color: colors.gray }]}
>
{item.Date}
</Text>
<View
style={{
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Text
style={[styles.cartItemPriceText, { color: colors.black }]}
>
AED {item.Total}
</Text>
<View
style={[
styles.statusWrapper,
{ backgroundColor: colors.primary },
]}
>
<Text style={[styles.statusText, { color: colors.white }]}>
{item.Status}
</Text>
</View>
</View>
</View>
<Image
source={{
uri: `${domain}${item.ShopPicture}`,
}}
style={styles.cardItemImage}
/>
</View>
</TouchableOpacity>
</LinearGradient>
</View>);
}
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<StatusBar style={theme.dark ? "light" : "dark"} />
<CustomLoading isLoading={isLoading} />
<FlatList
data={model.data}
renderItem={renderCardItems}
keyExtractor={(item, index) => item.InvoiceNo + "_" + index}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
style={{ marginTop: sizes.m10 }}
style={{
paddingVertical: sizes.m10,
backgroundColor: colors.background,
}}
/>
</View>

you can use navigation.push('screanName') instead of navigation.navigate('screenName')

Related

How do I prevent data in all other component views on a page from being cleared(rerendering) whenever I start to enter data in other view components?

On a gallery page, I have a text input field that allows the user to describe the kind of pictures and submit or share with a friend.
When I start to type in the text input field, the images in the gallery are cleared(the page re-renders) and all other input fields or component holding data are cleared.
I need help, how to prevent all data from other components from getting cleared whenever I start to enter data in view component on the page.
I am using functional components in my react native app.
export default function EvidenceSubmission ({route, navigation,navigation:{setParams}}){
//Incidence
const [state, setState]= useState({
selectedIncidence: 'select incidence',
photos:[],
});
/**
*clears images in async storage
*/
const clearStorage= async() =>{
try{
await AsyncStorage.clear();
} catch(exception){
console.log('error clearing items');
}
console.log('items cleared (Evidence Page)');
}
useEffect(()=> {
/*Get images from async storage*/
const getData = async () => {
try {
const value = await AsyncStorage.getItem('photos')
if(value !==null){
setState({
photos: (JSON.parse(value)).reverse(),
})
}
}catch(e){
console.log('error with async getData');
}
}
getData();
}, []);
/navigates to photo preview page/
const navigateToPhotoPreview = (path) =>{
navigation.navigate('PhotoPreviewer',
{
transferredImageItem: path,
})
}
return(
<SafeAreaView style= {globalStyle.MainContainer}>
<StatusBar barStyle="light-content" backgroundColor="#174060"/>
<View flexDirection='column' flex={0.456} marginTop={30}
marginRight ={5}
marginLeft ={5}
borderWidth={0.5}
borderRadius={3}
borderColor='#7E7E7E'>
<View>
<FlatList
data= {state.photos}
keyExtractor={(item, index)=> index}
renderItem={ ({ item}) => (
<TouchableOpacity onPress={() => navigateToPhotoPreview(item) }>
<Image
style={{ width:70, height:75,margin:0.5, resizeMode:'cover'}}
source = {{ uri: "file://"+ item}}
// source = {{ uri: item}}
//source = {{ uri: item.node.image.uri}}
/>
</TouchableOpacity>
)
}
numColumns = {5}
/>
</View>
</View>
<TouchableOpacity style={styles.addPhotoButton}
onPress={()=>{navigation.goBack()}}>
<Add
name={'add'}
size={30}
color="white"
/>
</TouchableOpacity>
<View style={{justifyContent: 'center', margin:5 ,flex: 1.2}}>
<View style={{borderWidth: 1,
borderColor:'#C4C4C4',
borderRadius:5,
width: 270,
marginLeft: 5,
marginBottom: 0,
marginTop: 15}}>
<Picker
selectedValue ={state.selectedIncidence}
style={{height:45, width: 270,
fontFamily:'roboto',
fontStyle:'normal',
fontWeight:'normal'}}
onValueChange={(itemValue, itemIndex) =>
setState({selectedIncidence: itemValue})
}
>
<Picker.Item label="Non-Compliance" value="Non-Compliance"/>
<Picker.Item label="Logistics" value="Logistics"/>
<Picker.Item label="Harassment" value="Harassment"/>
</Picker>
</View>
<View marginBottom={0} marginLeft={5} marginTop={15}>
<Text style={styles.textStyle}>
Description
</Text>
</View>
<View style={{flexDirection:'row'}} >
<View>
<TextInput
style={{height: 70,
width: 270,
borderRadius: 8,
borderColor:'#C4C4C4',
borderWidth: 1, marginLeft: 5}}
onChangeText={(text) => setState({text})}
value={state.text}
multiline={true}
enablesReturnKeyAutomatically={true}>
</TextInput>
</View>
<TouchableOpacity style={styles.microphoneButton}>
<Microphone name="microphone"
size={21}
color='white'
/>
</TouchableOpacity>
</View>
<View marginBottom={0} marginLeft={0} marginTop={15} marginBottom={15} >
<View style={{flexDirection: 'row'}}>
<Text style={{margin:10,marginRight:20,
fontFamily:'roboto', fontSize: 14,
fontWeight:'bold',
}}>
Submit as
</Text>
<View style={styles.radioCircumference}>
<TouchableOpacity style={styles.radioButton}></TouchableOpacity>
</View>
<Text style={{marginLeft: 5, marginRight: 0, marginTop: 10}}>anonymous</Text>
<Text style={{marginLeft: 10, marginRight: 10, marginTop: 10, fontWeight:'bold'}}> or </Text>
<View style={styles.radioCircumference}>
<TouchableOpacity style={styles.radioButton}></TouchableOpacity>
</View>
<Text style={{marginTop: 10,marginLeft: 5, marginRight: 0}}>Sign In</Text>
</View>
</View>
<TouchableOpacity
style={styles.button}
onPress={()=>clearStorage()}
>
<Text style={{color:'white',
alignSelf:'center',
fontSize: 18,
}}>
Next
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
Ok, so the first issue here is that you are mutating the state of setState. You are using the same state for your TextInput and Picker components. There are two ways to go about this.
1.Using the same state as u are doing.
const [formState, setFormState] = useState({
selectedIncidence: 'select incidence',
text: "",
photos: [],
});
In this case, when your onChangeText and onValueChange will be
onValueChange = {
(itemValue, itemIndex) =>
setFormState(formState => ({
...formState,
selectedIncidence: itemValue
}))
}
onChangeText = {
(text) => setFormState(formState => ({
...formState,
text
}))
}
2.The second approach is to use different states for each field.
const [selectedIncidence, setSelectedIncidence] = useState('select incidence');
const [text, setText] = useState("");
const [photos, setPhotos] = useState([]);
In this case, when your onChangeText and onValueChange will be
onValueChange = {
(itemValue, itemIndex) =>
setSelectedIncidence(itemValue)
}
onChangeText = {
(text) => setText(text)
}
I hope you find this helpful.

React Native Firestore Collection doesnt Render Flatlist

So basically I retrive a collection from Firestore succesfully and succesfully I put it in an array but it doesnt display on the screen, issue is I would say where I wrote paramater post inside my renderPost function. Please help me this should be easy I guess, this is my code:
<!-- language-all: lang-js -->
import Fire, { getPosts } from "../Fire";
import firebase, { database } from "firebase";
require("firebase/firestore");
export default class HomeScreen extends React.PureComponent {
constructor(props) {
super(props);
}
state = {
loading: false,
limit: 2,
post: [],
user: {},
};
onPostsReceived = (post) => {
this.setState({ post: post });
console.log(this.state.post); //it DOES return an array full of objects of collection
};
componentDidMount() {
getPosts(this.onPostsReceived);
//console.log(this.state.post); //returns empty array
}
renderPost = (post) => {
return (
<View style={styles.feedItem}>
<Image
source={
this.state.user.avatar
? { uri: this.state.user.avatar }
: require("../assets/tempAvatar.jpg")
}
style={styles.avatar}
/>
<View style={{ flex: 1 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<View>
{/* <Text>{console.log(this.state.post)}</Text> */}
<Text style={styles.name}>{}</Text>
<Text style={styles.timestamp}>
{moment(post.timestamp).toDate().toDateString()}
</Text>
</View>
<Ionicons name="ios-more" size={24} color="#73788B" />
</View>
<Text style={styles.post}>{post.text}</Text>
<Image
source={post.image && { uri: post.image }}
style={styles.postImage}
resizeMode="cover"
/>
<View style={{ flexDirection: "row" }}>
<Ionicons
name="ios-heart-empty"
size={24}
color="#73788B"
style={{ marginRight: 16 }}
/>
<Ionicons name="ios-chatboxes" size={24} color="#73788B" />
</View>
</View>
</View>
);
};
render() {
return (
<View style={styles.container}>
<StatusBar
translucent
backgroundColor="white"
barStyle="dark-content"
/>
<ClassicHeader
headerTitle="Eleph"
leftComponent={
<TouchableOpacity
style={{ marginRight: 0, margin: 10 }}
onPress={() =>
this.props.navigation.dispatch(DrawerActions.openDrawer())
}
>
<FontAwesome5 name="bars" size={24} color="#161924" />
</TouchableOpacity>
}
rightComponent={
<TouchableOpacity
style={{ marginLeft: 0, margin: 10 }}
onPress={() => this.props.navigation.navigate("Message")}
>
<Ionicons name="ios-chatboxes" size={24} color="#73788B" />
</TouchableOpacity>
}
/>
<FlatList
style={styles.feed}
data={this.state.post}
//extraData={this.state}
renderItem={({ item, index }) => {
this.renderPost(item);
}}
keyExtractor={(item, index) => String(index)}
//ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter}
ListHeaderComponent={this.renderHeader}
onEndReachedThreshold={0}
onEndReached={this.retrieveMore}
showsVerticalScrollIndicator={false}
></FlatList>
</View>
);
}
}
in case my method getPosts from Fire is important here it goes:
export async function getPosts (PostsRetreived) {
var post = [];
var snapshot = await firebase.firestore()
.collection('posts')
.orderBy('timestamp')
.get()
snapshot.forEach((doc) => {
const PostItem = doc.data();
PostItem.id = doc.id;
post.push(PostItem);
});
PostsRetreived(post);
}
Fire.shared = new Fire();
export default Fire;
Omfg...this is why I often hate programming. I lost a week to this and error was this:
renderItem={({ item, index }) => {
this.renderPost(item);
}}
should be renderItem={({ item, index }) =>
this.renderPost(item);
}
yeah i just had to delete one curly bracets, nothing anywhere pointed at this being problematic omg. anyways yeah bye

componentWillReceiveProps not triggering from child screen inside Tabview

I'm new in React native here. I got stuck on this scenario. I have a Dashboard screen. Inside dashboard screen, there's Hitcher screen that has Tabview. And there are HitcherTrip and HitcherChat inside the Tabview. In HitcherTrip, i expected componentWillReceiveProps() will trigger after calling Actions.goToOtherLayout() but componentWillReceiveProps() is triggered on Dashboard screen (Parent screen).
Dashboard
const Menu = createDrawerNavigator(
{
First: { screen: Hitcher },
Second: { screen: Driver }
},
{
contentComponent: props => (
<ScrollView>
<View style={{ padding:20, backgroundColor:'#4ca858' }}>
<Image source={require('../assets/pp.png')} style={{ borderRadius: 40, borderWidth: 1, borderColor: '#fff',width:80, height: 80 }} />
<CustomDrawerText/>
</View>
<SafeAreaView forceInset={{ top: "always", horizontal: "never" }}>
<Drawer.Item
label="I am Hitcher"
style={styles.drawerItem}
onPress={
() => {}
}
/>
<View style={{ height:1, backgroundColor:'#a8a8a8', marginLeft: 15, marginRight: 15 }}/>
<Drawer.Item
label="I am Driver"
onPress={
() => {}
}
style={styles.drawerItem}
/>
<View style={{ height:1, backgroundColor:'#a8a8a8', marginLeft: 15, marginRight: 15 }}/>
<Drawer.Item
label="Settings"
style={styles.drawerItem}
/>
<View style={{ height:1, backgroundColor:'#a8a8a8', marginLeft: 15, marginRight: 15 }}/>
<Drawer.Item
label="Log Out"
style={styles.drawerItem}
onPress={
() => {}
}
/>
<View style={{ height:1, backgroundColor:'#a8a8a8', marginLeft: 15, marginRight: 15 }}/>
</SafeAreaView>
</ScrollView>
)
}
);
const AppNav = createAppContainer(Menu);
export default class Dashboard extends React.Component {
constructor(props) {
super(props)
}
componentWillReceiveProps(props) {
console.log("Dashboard");
}
render() {
return(
<AppNav />
)
}
}
Hitcher
export default class Hitcher extends React.Component {
state = {
index: 0,
routes: [
{ key: 'first', title: 'My Trips' },
{ key: 'second', title: 'Chats' },
],
};
async _storeItem(key, token) {
try {
var token = await AsyncStorage.setItem(key, token);
return token;
} catch (error) {
console.log(error.message);
}
}
render() {
return (
<View style={styles.container}>
<Appbar.Header
style={{ backgroundColor: '#4ca858' }}>
<Appbar.Action
icon="menu"
color="white"
onPress={() =>
this.props.navigation.dispatch(DrawerActions.toggleDrawer())
}
/>
<Appbar.Action icon={require('../assets/logo_inverted.png')} style={{flex:1, alignSelf:'center'}} size={65} color="white"/>
<Appbar.Action icon="bell" color="white"/>
</Appbar.Header>
<View style={styles.container}>
<TabView
style={{ marginTop: 10 }}
navigationState={this.state}
renderScene={SceneMap({
first: HitcherTrip,
second: HitcherChat,
})}
renderTabBar={props =>
<TabBar
{...props}
labelStyle={styles.label}
indicatorStyle={styles.indicator}
style={styles.tabbar}
getLabelText={({ route }) => route.title}
/>
}
onIndexChange={index => this.setState({ index })} />
</View>
</View>
);
}
}
HitcherTrip
export default class HitcherTrip extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isFetching: false,
spinner: false,
itemId: 0
};
}
componentDidMount() {
this.getTrips();
}
getTrips = () => {
// codes
};
componentWillReceiveProps(props) {
console.log("HitcherTrip");
}
onRefresh() {
this.setState({isFetching: true,},() => {this.getTrips();});
}
createTrip = () => {
Actions.goToOtherLayout();
};
render() {
return(
<View style={styles.scene} >
<FlatList
showsVerticalScrollIndicator={false}
data={this.state.data}
renderItem={({item}) => {
var date = Moment(item.created_at).format('DD MMM');
var now = Moment();
var expired = Moment(item.expired_at);
var status = item.status_name;
if (now > expired && item.status == 0)
status = "Expired";
return (
<TouchableOpacity onPress={
() => {
}
}>
<Spinner
visible={this.state.spinner}
textContent={'Loading...'}
textStyle={styles.spinnerTextStyle}
/>
<View style={styles.container}>
{item.status == 0 ?
<View style={styles.header}>
<Text style={styles.headerLeftActive}>{status}</Text>
<Text style={styles.headerRightActive}>{item.request_no}</Text>
</View> :
<View style={styles.headerInActive}>
<Text style={styles.headerLeftInactive}>{status}</Text>
<Text style={styles.headerRightInactive}>{date}</Text>
</View>
}
<View style={styles.content}>
<Image source={require('../assets/fromto.png')} style={styles.image} />
<View style={styles.textContent}>
<Text style={styles.address}>{item.pickup_location}</Text>
<View style={{flex: 1}} />
<Text style={styles.address}>{item.dropoff_location}</Text>
</View>
</View>
</View>
</TouchableOpacity>
)}
}
keyExtractor={item => item.request_no}
onRefresh={() => this.onRefresh()}
refreshing={this.state.isFetching}
/>
<TouchableOpacity
style={{
alignItems:'center',
justifyContent:'center',
width:70,
position: 'absolute',
bottom: 10,
right: 10,
height:70,
backgroundColor:'#4ca858',
borderRadius:100,
elevation: 6,
}} onPress={this.createTrip}>
<Text style={{color:'#fff', fontSize: 32}}>+</Text>
</TouchableOpacity>
</View>
)
}
}
On other layout, i have set
Actions.pop(); setTimeout(()=> Actions.refresh(), 500);
to trigger componentWillReceiveProps() when press back button. But it only triggers on Dashboard screen.
How to trigger componentWillReceiveProps() on HitcherTrip? Or maybe trigger HitcherTrip function from Dashboard screen?

TypeError: Cannot read property of 'data' of undefined

I am using <FlatList/> to render an item for each object of json. This json is stored in this.state.json. Here is my code:
export class MyAppsName extends React.Component {
static navigationOptions = {
title: "App name",
headerLeft: null,
};
constructor() {
super();
this.state = {
index: 0,
isAuthed: false,
data: [
{
name: "Class 1",
grade: 83,
letterGrade: "A+"
},
{
name: "Class 2",
grade: 90,
letterGrade: "B+"
}
],
loading: false
};
}
refresh() {
this.setState({ isAuthed: true });
}
componentWillMount() {
}
render() {
return (
<Root>
<ScrollableTabView initialPage={0} tabBarPosition="top">
<HomeRoute tabLabel="Grades" />
<View
style={{ flex: 1, justifyContent: "center" }}
tabLabel="Settings"
>
</View>
</ScrollableTabView>
</Root>
);
}
}
makeRemoteRequest = () => {
//do request stuff
};
handleRefresh = () => {
this.makeRemoteRequest();
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "black",
}}
/>
);
};
renderHeader = () => {
return <View />;
};
classSelected = className => {
//do stuff
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View>
<ActivityIndicator animating size="large" />
</View>
);
};
const HomeRoute = () => (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
style={{ width: width }}
data={this.state.data}
renderItem={({ item }) => (
<View style={{ left: "9%", padding: 6 }}>
<TouchableOpacity onPress={() => this.classSelected(item.name)}>
<Text
style={{
fontSize: 16
}}
>
{item.name}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.grade}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.letterGrade}
</Text>
</TouchableOpacity>
</View>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
keyExtractor={item => item.name}
/>
</List>
);
The error I get is 'TypeError: Cannot read property 'data' of undefined' within HomeRoute. I think the error is in this line: data={this.state.data}.
I am defining data correctly? Am I even correctly setting up the FlatList? Or does it have to do with how I am passing down application state?
If you need any other code to be appended to the question, you can just ask in the comments.
Thanks in advance
You've declared the state in is parent component, causing this.state is undefined in its child component.
When you use the HomeRoute component, you need to pass the state data from its parent component.
render() {
return (
<Root>
<ScrollableTabView initialPage={0} tabBarPosition="top">
<HomeRoute tabLabel="Grades" data={this.state.data} />
<View
style={{ flex: 1, justifyContent: "center" }}
tabLabel="Settings"
>
</View>
</ScrollableTabView>
</Root>
);
}
and in the HomeRoute itself, you need to extract data from its props.
const HomeRoute = ({data}) => (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
style={{ width: width }}
data={data}
renderItem={({ item }) => (
<View style={{ left: "9%", padding: 6 }}>
<TouchableOpacity onPress={() => this.classSelected(item.name)}>
<Text
style={{
fontSize: 16
}}
>
{item.name}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.grade}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.letterGrade}
</Text>
</TouchableOpacity>
</View>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
keyExtractor={item => item.name}
/>
</List>
);
Several functions, including HomeRoute, are not defined within the MyAppsName class. Therefore, this in these functions doesn't point to the correct this. I suggest to put them inside the class and bind all the functions that use this.
You get a syntax error because they are not defined properly. Follow the pattern of the definition of render, for example:
makeRemoteRequest() {
Instead of
makeRemoteRequest = () => {

Like functionality like Facebook react native

I am using a list of image.Below every image,there is a like button. When i click on the Like button, likes should be increases which is working fine. But it should work on the image I click. Currently it is increasing like count of all the images.I am new to react native.Any help would be appreciated.
Here, this is my code
export default class Art extends Component {
constructor(props) {
super(props)
this.state = {
value: null,
liked:false
}
}
_increaseValue(){
console.log(this.state.liked)
if (this.state.liked==false)
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value +1;
this.setState({value:newvalue})
}
else
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value -1;
this.setState({value:newvalue}
}
}
render() {
const datas = [
{
img: images[0]
},
{
img: images[1]
},
{
img: images[2]
},
{
img: images[3]
},
];
const { navigate } = this.props.navigation;
// eslint-disable-line
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data =>
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.value} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
/>
</Content>
);
}
}
You need to convert your Cards into separate components or store the like counts separately in state. You can approach this problem several ways. I'll give you an example of how you can achieve this behavior and you can implement it the way you like.
Example
export default class CutomListItem extends React.Component {
constructor(props) {
this.state = {
likes: 0
};
}
_increaseValue = () => {
this.setState((prevState) => {
return {
likes: prevState.likes++
};
});
}
render() {
const { data, navigate, share } = this.props; // send data with props
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.likes} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
}
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data => (<CutomListItem data={data} navigate={navigate} share={Share} />}
/>
</Content>
);
}