How to set Json array from flatlist in react native - javascript

I am new in react native . i am get data from asynstorage. how to set that data from flatlist. my problem is can not set value properly in flatlist data. herewith below attached the JSon value and my code. am try to long time but no idea for that please help me. please
I get data to asystorage value Json Data
{
"users":[
{
"title":"Opna Women's Short Sleeve Moisture",
"image":"https://fakestoreapi.com/img/51eg55uWmdL._AC_UX679_.jpg",
"id":19
},
{
"title":"DANVOUY Womens T Shirt Casual Cotton Short",
"image":"https://fakestoreapi.com/img/61pHAEJ4NML._AC_UX679_.jpg",
"id":20
}
]
}
Main code.
import React, { useState } from 'react';
import { SafeAreaView, StyleSheet, View, Text, Image, Alert, TouchableOpacity } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialIcons';
import COLORS from '../../consts/colors';
import foods from '../../consts/foods';
import { PrimaryButton } from '../components/Button';
import AsyncStorage from '#react-native-async-storage/async-storage';
const CartScreen = ({ navigation }) => {
const [value, setvalue] = useState(true);
AsyncStorage.getItem('storeddata')
.then((value) => {
setvalue(value)
console.log("saveddata", value);
}
)
const CartCard = ({ item }) => {
console.log("itemlist", item);
return (
<View style={style.cartCard}>
<Image source={{ uri: item.image }} style={{ height: 80, width: 80 }} />
<View
style={{
height: 100,
marginLeft: 10,
paddingVertical: 20,
flex: 1,
}}>
<Text style={{ fontWeight: 'bold', fontSize: 16 }}>{item.title}</Text>
<Text style={{ fontSize: 13, color: COLORS.grey }}>
{item.title}
</Text>
<Text style={{ fontSize: 17, fontWeight: 'bold' }}>${item.id}</Text>
</View>
<View style={{ marginRight: 20, alignItems: 'center' }}>
<Text style={{ fontWeight: 'bold', fontSize: 18 }}>5</Text>
<View style={style.actionBtn}>
<Icon name="remove" size={25} color={COLORS.white} />
<Icon name="add" size={25} color={COLORS.white} />
</View>
</View>
</View>
);
};
return (
<SafeAreaView style={{ backgroundColor: COLORS.white, flex: 1 }}>
<View style={style.header}>
<Icon name="arrow-back-ios" size={28} onPress={navigation.goBack} />
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>Cart</Text>
</View>
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={{ paddingBottom: 80 }}
data={value}
renderItem={({ item }) => <CartCard item={item} />}
ListFooterComponentStyle={{ paddingHorizontal: 20, marginTop: 20 }}
ListFooterComponent={() => (
<View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 15,
}}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
Total Price
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>$50</Text>
</View>
<View style={{ marginHorizontal: 30 }}>
<PrimaryButton title="CHECKOUT" onPress={() => navigation.navigate('Checkout')} />
</View>
</View>
)}
/>
</SafeAreaView>
);
};
const style = StyleSheet.create({
header: {
paddingVertical: 20,
flexDirection: 'row',
alignItems: 'center',
marginHorizontal: 20,
},
cartCard: {
height: 100,
elevation: 15,
borderRadius: 10,
backgroundColor: COLORS.white,
marginVertical: 10,
marginHorizontal: 20,
paddingHorizontal: 10,
flexDirection: 'row',
alignItems: 'center',
},
actionBtn: {
width: 80,
height: 30,
backgroundColor: COLORS.primary,
borderRadius: 30,
paddingHorizontal: 5,
flexDirection: 'row',
justifyContent: 'center',
alignContent: 'center',
},
});
export default CartScreen;

Flatlist data props take an array as an input Official doc
you are getting an object from local storage you have to pass an array to it
local storage save string value so you have to do JSON.stringify() it when you store data in it and JSON.parse() it when getting data from local storage
local storage link

If your value have that above JSON data stored then try to pass prop like:
<FlatList
...
data={value.users}
...
/>
Hope this works for you.

Related

Error : undefined is not an object (evaluating 'source')

I'm using WordPress API in my react native app. Everything is working fine except my single post screen. I'm requesting post data, updating state, and rendering data from the state. My app was crashing after going on this screen. I spend hours and I've found out what's the problem however don't how to fix it.
My Screen Code -
import React, { useState, useEffect } from "react";
import {
ActivityIndicator,
Text,
View,
ScrollView,
Image,
useWindowDimensions,
} from "react-native";
import HTMLView from "react-native-htmlview";
import globalStyles from "../constant/globalStyle";
import axios from "axios";
import moment from "moment";
import { Colors } from "../constant/colors";
const PostDetail = ({ route }) => {
const { postId } = route.params;
const [postData, setPostData] = useState({});
const [loaded, setLoaded] = useState(false);
const [source, setSource] = useState("");
useEffect(() => {
const fetchData = async () => {
await axios
.get(
`https://bachrasouthpanchayat.in/wp-json/wp/v2/posts/${postId}?embed=true`
)
.then((response) => {
setPostData(response.data);
setSource(response.data.content.rendered);
setLoaded(true);
})
.catch((error) => console.log(error, error.message));
};
fetchData();
}, []);
const { width } = useWindowDimensions();
return (
<ScrollView
style={{
...globalStyles.container,
backgroundColor: Colors.BACKGROUND_SCREEN,
}}
>
{loaded ? (
<>
<Image
style={{
width: "100%",
height: 250,
}}
source={{ uri: postData.jetpack_featured_media_url }}
resizeMode="cover"
/>
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered}
</Text>
<View style={{ paddingHorizontal: 18 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 10,
}}
>
<Text
style={{
...globalStyles.date,
fontSize: 20,
fontWeight: "700",
}}
>
{moment(postData.date).format("LL")}
</Text>
</View>
<HTMLView
stylesheet={{
p: { fontSize: 20, color: "white", textAlign: "justify" },
h1: {
color: "white",
fontSize: 32,
},
h2: {
color: "white",
fontSize: 28,
},
figure: {
backgroundColor: "red",
width: "100% !important",
height: "100% !important",
},
img: {
width: "100% !important",
backgroundColor: "green",
},
}}
value={source}
imagesMaxWidth={width}
/>
</View>
</>
) : (
<View
style={{
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size={60} color={Colors.PRIMARY_GREEN} />
</View>
)}
</ScrollView>
);
};
export default PostDetail;
I've used a bunch of console log statements and found out that "when useEffect runs the request is sent to API but it didn't stay on that line of code to receive a response, instead remaining lines of codes are executed and that's why I was getting the undefined error". However, the state gets updated after some time but I still get the error.
I have used async & await but don't know why all those remaining lines of codes ran before getting a response.
When this page is rendered for the first time, your postData is an empty object:
const [postData, setPostData] = useState({});
and at this point of time you try to access it's children (but it doesn't have them yet):
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered} // here you access the empty object
</Text>
Then the useEffect is called which populates that postData
The solution (just add the question mark after postData.title?.rendered):
<Text style={globalStyles.primaryHeading}>
{postData.title?.rendered}
</Text>
The better solution is to show loading until you have not fetched the component:
if(postData.title?.rendered)
return <ActivityIndicator size={24} color={"#424242"} />
return (
<ScrollView
style={{
...globalStyles.container,
backgroundColor: Colors.BACKGROUND_SCREEN,
}}
>
{loaded ? (
<>
<Image
style={{
width: "100%",
height: 250,
}}
source={{ uri: postData.jetpack_featured_media_url }}
resizeMode="cover"
/>
<Text style={globalStyles.primaryHeading}>
{postData.title.rendered}
</Text>
<View style={{ paddingHorizontal: 18 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 10,
}}
>
<Text
style={{
...globalStyles.date,
fontSize: 20,
fontWeight: "700",
}}
>
{moment(postData.date).format("LL")}
</Text>
</View>
<HTMLView
stylesheet={{
p: { fontSize: 20, color: "white", textAlign: "justify" },
h1: {
color: "white",
fontSize: 32,
},
h2: {
color: "white",
fontSize: 28,
},
figure: {
backgroundColor: "red",
width: "100% !important",
height: "100% !important",
},
img: {
width: "100% !important",
backgroundColor: "green",
},
}}
value={source}
imagesMaxWidth={width}
/>
</View>
</>
) : (
<View
style={{
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size={60} color={Colors.PRIMARY_GREEN} />
</View>
)}
</ScrollView>

How do i set and get the different states and inputs from a flatlist with multiple objects

ok i got this flatlist contained within a flatlist, and the flatlist from inside, contains dropdowns, inputs, and buttons that i need to capture which data i'm getting from them, and of course save the new data based on what i selected, typed in or clicked, i'm not entirely sure how to do this, this is the code for flatlist
<FlatList
extraData = {this.state}
data = {this.state.dataSource}
renderItem = {({item, index}) => {
return (
<View style={{marginTop: hp('2%')}}>
<TouchableOpacity style={{
alignSelf: 'center',
width: wp('95.7%'),
height: hp('10%'),
backgroundColor: "#ffffff",
}} onPress={() => this.toggleExpanded()}>
<View style={{flex: 1, flexDirection: 'row', justifyContent: 'space-between'}}>
<View style={{flexDirection: 'column', justifyContent: 'center'}}>
<Text numberOfLines={2} ellipsizeMode="tail" style={{
marginLeft: wp('5%'),
width: wp('55%'),//wp('38.2%'), //151
//height: hp('2%'), //19
fontSize: rfv(16),
fontWeight: "500",
fontStyle: "normal",
textAlign: "left",
color: "#707070"
}}>{item.Title}</Text>
<Text style={{
marginLeft: wp('5%'),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#c4c4c4"
}}>{`ID ${item.Id} - ${item.Cliente}`}</Text>
{
!item.IsFavorite ?
<Text style={{
marginLeft: wp('5%'),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "italic",
textAlign: "left",
color: "#c4c4c4"
}}>No favorito</Text>
: null
}
</View>
<View style={{flexDirection: 'column', justifyContent: 'center'}}>
<View style={{flexDirection: 'row', marginRight: wp('3.4%')}}>
<Text style={{
fontSize: rfv(18),
fontWeight: "300",
fontStyle: "normal",
textAlign: "right",
color: "#707070"}}>{`${0}h`}</Text>
<Image style={{marginTop: hp('1%'), marginLeft: wp('3.7%')}} source={this.state.isCollapsed ? Images.expandible : Images.collapsible}/>
</View>
</View>
</View>
</TouchableOpacity>
<Collapsible style={{
alignSelf: 'center',
width: wp('95.7%'),
backgroundColor: "#ffffff",}} collapsed={this.state.isCollapsed}>
<FlatList
//extraData = {this.state}
data = {item.ListReportHistoryResponse}//{DataManager.FavoriteList[moment(this.state.selectedDate).format('YYYY-MM-DD')]}
renderItem = {({ item, index }) => {
return (
<View>
<View style={{flexDirection: 'row'}}>
<Text style={{
marginLeft: wp('5%'),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171"
}}>Etapa</Text>
<Text style={{
marginLeft: wp('42.5%'),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171"
}}>Horas</Text>
</View>
<View style={{flexDirection: 'row'}}>
<ModalDropdown
adjustFrame={style => {
style.top =(Platform.OS === 'ios' ? style.top : style.top - StatusBar.currentHeight);
return style;
}}
dropdownTextStyle={styles.dropdownTextStyle}
dropdownTextHighlightStyle={styles.dropdownTextHighlightStyle}
dropdownStyle={styles.dropdownStageStyle}
defaultValue={item.Etapa}
style={styles.dropStageStyle}
textStyle={{
padding: 0,
margin: 0,
fontSize: rfv(16),
paddingVertical: hp('1.2%'),
fontWeight: 'normal',
fontStyle: 'normal',
textAlign: 'left',
color: item.Etapa /*item.ListReportHistoryResponse[index2].Etapa*/ != 'Selecciona una etapa' ? '#1a1a1a' : '#c4c4c4',
}}
//onSelect={(index, value) => this.setState({SeleccionClientes: value})}
//options={Object.keys(this.state.items)}
onSelect={(index, value) => this.setState({SeleccionClientes: value})}
options={DataManager.ListEtapa}
/>
<View style={styles.InputContainerHours}>
<Text style={styles.InputTextHours}>{item.HorasTrabajadas}</Text>
</View>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('5.5%')}} onPress={() => this.props.onSubstract}>
<Image source={Images.menos_hora}/>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('2%')}} onPress={() => this.props.onAdd}>
<Image source={Images.mas_hora}/>
</TouchableOpacity>
</View>
<Text style={{
fontSize: rfv(14),
marginLeft: wp('5%'),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171"
}}>Observaciones</Text>
<Input
autoCapitalize="none"
maxLength={100}
inputContainerStyle={styles.InputContainerComentarioOnBlur}
containerStyle={styles.InputComentario}
inputStyle={styles.InputTextHoursRInput}
placeholderTextColor={'#c4c4c4'}
placeholder="(Opcional)"
onChangeText={value => this.setState({})}
/>
<TouchableOpacity style={{alignItems: 'flex-end', alignSelf: 'flex-end'}}>
<Text style={{
marginRight: wp('3.4%'),
marginBottom: hp('3%'),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#1062cc"
}}>Agregar etapa</Text>
</TouchableOpacity>
</View>
)}}/>
</Collapsible>
</View>
)
}}
/>
EDIT: updated with screenshot of the object displayed in flatlist, i still need help getting this to work
<View style={styles.InputContainerHours}>
<Text style={styles.InputTextHours}>{item.HorasTrabajadas}</Text>
</View>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('5.5%')}} onPress={() => this.props.onSubstract}>
<Image source={Images.menos_hora}/>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('2%')}} onPress={() => this.props.onAdd}>
<Image source={Images.mas_hora}/>
</TouchableOpacity>
the onadd is supposed function that adds to item.HorasTrabajadas, 0.5 in addition to the current value, and the onsubstract is the same but substracts to the current value
and here is the object
edit 2: what if the api contains an object with data saved already, how do i edit that new data?
edit 3: i added a github project with the 3 most important parts of this project, https://github.com/Vasault/HourReg/tree/develop contains 3 files, the most important one HourRegistration.tsx
edit 4: unable to change data that already come from api
You can use the index of your array to identify the selected item, and when you have an index of every time you can update the item on every action according to your need.
Let suppose you have 10 items and on every item, you have to update the state you can get the item and index of that row and can update the state easily.
Here is a simple example that can clear your confusion.
And here is a snack with a working example
https://snack.expo.io/#waheed25/radarada
import React from 'react';
import { SafeAreaView, View, TextInput, FlatList, StyleSheet, Text } from 'react-native';
import Constants from 'expo-constants';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
export default class App extends React.Component {
state={
observacionesInput: []
}
onTextObservacionesChange = (text, index) => {
var { observacionesInput } = this.state
let myArray = observacionesInput
myArray[index] = text
this.setState({observacionesInput: myArray });
}
toggleExpanded = () => {
this.setState({ isCollapsed: !this.state.isCollapsed });
};
render(){
console.log('state', this.state)
return (
<SafeAreaView>
<Text>Testing</Text>
<FlatList
data={DATA}
renderItem={({ item, index }) => {
return(
<View style={{ marginTop: 20}}>
<TextInput
style={{borderColor: 'gray', borderWidth: 1, height: 50,}}
autoCapitalize="none"
maxLength={100}
placeholderTextColor={'#c4c4c4'}
placeholder="(Opcional)"
onChangeText={value => this.onTextObservacionesChange(value, index)}
/>
</View>
)
}}
/>
</SafeAreaView>
);
}
}
you can make dynamic state by append parentIndex and childIndex to state to uniquely identify of item of child flatlist
you can use onChangeValue for save data into newDataSave object and getDataFromNewSave for get data from newDataSave
Note: you all saving data is saving in newDataSave object. you can console to check it and save into database.
onChangeValue = (key, value) => {
this.setState((prevState) => {
return {
newDataSave: {
...prevState.newDataSave,
[key]: value,
},
};
});
};
getDataFromNewSave = (key) => {
try {
return this.state.newDataSave[key];
} catch (error) {
return "";
}
};
<Input
value={this.getDataFromNewSave(
`input${parentIndex}${childIndex}`
)}
autoCapitalize="none"
maxLength={100}
inputContainerStyle={
styles.InputContainerComentarioOnBlur
}
containerStyle={styles.InputComentario}
inputStyle={styles.InputTextHoursRInput}
placeholderTextColor={"#c4c4c4"}
placeholder="(Opcional)"
onChangeText={(value) => {
this.onChangeValue(
`input${parentIndex}${childIndex}`,
value
);
}}
/>
Full Code:
import React, { Component } from "react";
import {
Text,
StyleSheet,
View,
FlatList,
TouchableOpacity,
Image,
TextInput,
} from "react-native";
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp,
} from "react-native-responsive-screen";
import Collapsible from "react-native-collapsible";
import ModalDropdown from "react-native-modal-dropdown";
const Input = TextInput;
const rfv = (value) => {
return value;
};
const DataManager = {
ListEtapa: ["a", "b", "c"],
};
const Images = {
collapsed: require("./assets/icons/app-icon.png"),
expandible: require("./assets/icons/app-icon.png"),
};
export default class App extends Component {
state = {
isCollapsed: false,
dataSource: [
{
Id: "1",
Title: "abc1",
Cliente: "abc1",
IsFavorite: false,
ListReportHistoryResponse: [
{ Etapa: "abc1", HorasTrabajadas: "abcabc1" },
{ Etapa: "cde1", HorasTrabajadas: "cdecde1" },
],
},
{
Id: "2",
Title: "abc2",
Cliente: "abc2",
IsFavorite: false,
ListReportHistoryResponse: [
{ Etapa: "abc2", HorasTrabajadas: "abcabc2" },
{ Etapa: "cde2", HorasTrabajadas: "cdecde2" },
],
},
],
newDataSave: {},
};
onChangeValue = (key, value) => {
this.setState((prevState) => {
return {
newDataSave: {
...prevState.newDataSave,
[key]: value,
},
};
});
};
getDataFromNewSave = (key) => {
try {
return this.state.newDataSave[key];
} catch (error) {
return "";
}
};
render() {
return (
<View>
<FlatList
extraData={this.state}
data={this.state.dataSource}
renderItem={({ item, index: parentIndex }) => {
return (
<View style={{ marginTop: hp("2%") }}>
<TouchableOpacity
style={{
alignSelf: "center",
width: wp("95.7%"),
height: hp("10%"),
backgroundColor: "#ffffff",
}}
onPress={() => this.toggleExpanded()}
>
<View
style={{
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
}}
>
<View
style={{
flexDirection: "column",
justifyContent: "center",
}}
>
<Text
numberOfLines={2}
ellipsizeMode="tail"
style={{
marginLeft: wp("5%"),
width: wp("55%"), //wp('38.2%'), //151
//height: hp('2%'), //19
fontSize: rfv(16),
fontWeight: "500",
fontStyle: "normal",
textAlign: "left",
color: "#707070",
}}
>
{item.Title}
</Text>
<Text
style={{
marginLeft: wp("5%"),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#c4c4c4",
}}
>{`ID ${item.Id} - ${item.Cliente}`}</Text>
{!item.IsFavorite ? (
<Text
style={{
marginLeft: wp("5%"),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "italic",
textAlign: "left",
color: "#c4c4c4",
}}
>
No favorito
</Text>
) : null}
</View>
<View
style={{
flexDirection: "column",
justifyContent: "center",
}}
>
<View
style={{
flexDirection: "row",
marginRight: wp("3.4%"),
}}
>
<Text
style={{
fontSize: rfv(18),
fontWeight: "300",
fontStyle: "normal",
textAlign: "right",
color: "#707070",
}}
>{`${0}h`}</Text>
<Image
style={{
marginTop: hp("1%"),
marginLeft: wp("3.7%"),
}}
source={
this.state.isCollapsed
? Images.expandible
: Images.collapsible
}
/>
</View>
</View>
</View>
</TouchableOpacity>
<Collapsible
style={{
alignSelf: "center",
width: wp("95.7%"),
backgroundColor: "#ffffff",
}}
collapsed={this.state.isCollapsed}
>
<FlatList
//extraData = {this.state}
data={item.ListReportHistoryResponse} //{DataManager.FavoriteList[moment(this.state.selectedDate).format('YYYY-MM-DD')]}
renderItem={({ item, index: childIndex }) => {
return (
<View>
<View style={{ flexDirection: "row" }}>
<Text
style={{
marginLeft: wp("5%"),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171",
}}
>
Etapa
</Text>
<Text
style={{
marginLeft: wp("42.5%"),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171",
}}
>
Horas
</Text>
</View>
<View style={{ flexDirection: "row" }}>
<ModalDropdown
adjustFrame={(style) => {
style.top =
Platform.OS === "ios"
? style.top
: style.top - StatusBar.currentHeight;
return style;
}}
dropdownTextStyle={styles.dropdownTextStyle}
dropdownTextHighlightStyle={
styles.dropdownTextHighlightStyle
}
dropdownStyle={styles.dropdownStageStyle}
defaultValue={this.getDataFromNewSave(
`SeleccionClientes${parentIndex}${childIndex}`
)}
style={styles.dropStageStyle}
textStyle={{
padding: 0,
margin: 0,
fontSize: rfv(16),
paddingVertical: hp("1.2%"),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color:
item.Etapa /*item.ListReportHistoryResponse[index2].Etapa*/ !=
"Selecciona una etapa"
? "#1a1a1a"
: "#c4c4c4",
}}
//onSelect={(index, value) => this.setState({SeleccionClientes: value})}
//options={Object.keys(this.state.items)}
onSelect={(i, value) =>
// this.setState({ SeleccionClientes: value })
this.onChangeValue(
`SeleccionClientes${parentIndex}${childIndex}`,
value
)
}
options={DataManager.ListEtapa}
/>
<View style={styles.InputContainerHours}>
<Text style={styles.InputTextHours}>
{item.HorasTrabajadas}
</Text>
</View>
<TouchableOpacity
style={{
marginTop: hp("0.5%"),
marginLeft: wp("5.5%"),
}}
onPress={() => this.props.onSubstract}
>
<Image source={Images.menos_hora} />
</TouchableOpacity>
<TouchableOpacity
style={{
marginTop: hp("0.5%"),
marginLeft: wp("2%"),
}}
onPress={() => this.props.onAdd}
>
<Image source={Images.mas_hora} />
</TouchableOpacity>
</View>
<Text
style={{
fontSize: rfv(14),
marginLeft: wp("5%"),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#717171",
}}
>
Observaciones
</Text>
<Input
value={this.getDataFromNewSave(
`input${parentIndex}${childIndex}`
)}
autoCapitalize="none"
maxLength={100}
inputContainerStyle={
styles.InputContainerComentarioOnBlur
}
containerStyle={styles.InputComentario}
inputStyle={styles.InputTextHoursRInput}
placeholderTextColor={"#c4c4c4"}
placeholder="(Opcional)"
onChangeText={(value) => {
this.onChangeValue(
`input${parentIndex}${childIndex}`,
value
);
}}
/>
<TouchableOpacity
style={{
alignItems: "flex-end",
alignSelf: "flex-end",
}}
>
<Text
style={{
marginRight: wp("3.4%"),
marginBottom: hp("3%"),
fontSize: rfv(14),
fontWeight: "normal",
fontStyle: "normal",
textAlign: "left",
color: "#1062cc",
}}
>
Agregar etapa
</Text>
</TouchableOpacity>
</View>
);
}}
/>
</Collapsible>
</View>
);
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({});
SOLVED, in a much better and easier way
on every input, dropdown, etc. set a function and pass 3 parameters
onChangeText={value => this.onChangeTextObservaciones(parentIndex, childIndex, value)
parentIndex (the one from outside flatlist), childIndex (the one from inside), and the value you're editing (blank or not)
const onChangeTextObservaciones = (indexOutside, indexInside, value) => {
this.dataList[indexOutside].ListReportHistoryResponse[indexInside].Title = value;
this.setState({displayDay: this.dataList});
}
change the specific value from the specific element from that object, and change it with the new value, and lastly change the whole new object with the new value.
a friend of mine realize this

I can't re-render the FlatList after empty data?

I Get the data from firebase real-time and put it I FlatList and when I delete if from Console "Firebase" it's deleted from the List in screen very well but the last item in the Array "Data" couldn't be deleted I don't know why!
I use an onRefresh Props but not help me because we all know the DB is real-time and when we will add any item it's will be in the last without refresh it So it's not work with the last item too and just the loading stuck without re-render the FlatList
Although I use .once('value') when I get data from DB, refresh work but when I refresh after deleting the last item the loading refresh stuck and can't disappear the last item
so how can I solve this issue?
here is my code
import auth from '#react-native-firebase/auth';
import database from '#react-native-firebase/database';
import React, {Component} from 'react';
import {
Dimensions,
FlatList,
Image,
Text,
TouchableOpacity,
View,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
const {width} = Dimensions.get('window');
export default class PendingOrders extends Component {
constructor(props) {
super(props);
this.state = {
orders: [],
forceUpdate: true,
isFetching: false,
};
}
onRefresh = () => {
this.setState({isFetching: true}, () => this.getApiData());
};
getApiData = () => {
try {
const uid = auth().currentUser.uid;
const Orders = database().ref(`usersOrders/${uid}`);
Orders.on('value', snapshot => {
let orders = [];
snapshot.forEach(childSnapshot => {
if (childSnapshot.val().status == 'pending') {
orders.push({
buildingNumber: childSnapshot.val().buildingNumber,
service: childSnapshot.val().categoryName,
date: childSnapshot.val().date,
time: childSnapshot.val().time,
description: childSnapshot.val().problemDescription,
status: childSnapshot.val().status,
images: childSnapshot.val().Images,
});
this.setState({orders, forceUpdate: false, isFetching: false}, () =>
console.log(this.state.orders),
);
return;
}
});
});
} catch (err) {
console.log('Error fetching data: ', err);
}
};
componentDidMount() {
this.getApiData();
}
_listEmptyComponent = () => {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}>
<Image
style={{
width,
height: width * 0.7,
resizeMode: 'contain',
}}
source={require('../../assets/empty.png')}
/>
<Text
style={{
color: '#000',
marginVertical: 15,
textAlign: 'center',
fontSize: 20,
}}>
No item found
</Text>
</View>
);
};
render() {
console.log('is?', this.state.forceUpdate);
return (
<FlatList
showsVerticalScrollIndicator={false}
data={this.state.orders}
extraData={this.state.isFetching}
onRefresh={() => this.onRefresh()}
ListEmptyComponent={this._listEmptyComponent()}
refreshing={this.state.isFetching}
contentContainerStyle={{
flexBasis: '100%',
}}
renderItem={({item}) => {
return (
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate('OrderDetailsScreen', {
service: item.service,
time: item.time,
date: item.date,
description: item.description,
images: item.images,
status: item.status,
})
}
style={{
margin: 15,
borderRadius: 10,
borderWidth: 1,
flexDirection: 'row',
borderColor: '#ddd',
}}>
<Image
style={{
borderRadius: 10,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
width: 150,
height: 150,
}}
resizeMode="cover"
source={item.images[0]}
/>
<View
style={{
margin: 5,
marginLeft: 10,
justifyContent: 'space-evenly',
}}>
<Text
style={{
marginBottom: 5,
fontWeight: 'bold',
fontSize: 16,
marginTop: 5,
}}>
{item.service}
</Text>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
// paddingHorizontal: 5,
}}>
<Icon name="date-range" color="#AEACAC" size={20} />
<Text style={{paddingHorizontal: 5}}>{item.date}</Text>
</View>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 5,
}}>
<Icon name="access-time" color="#AEACAC" size={20} />
<Text style={{paddingHorizontal: 5}}>{item.time}</Text>
</View>
</View>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={{marginBottom: 5, width: 160, marginTop: 5}}>
{item.description}
</Text>
</View>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => index.toString()}
/>
);
}
}
The key for re activating flatlist is extraData. just change it's value to something else and it will trigger flatlist re rendering. for simplicity pass a boolean value to extraData. every time you want to re active the flatlist, just toggle the value of extraData

Getting list from firebase and rendering it doesn't work

Problem
I am creating an app with react native and firebase where users can post to firebase, and then my app will render all of the posts. When I added the code to render the posts from firebase (flatlist), nothing renders. I convert the list from firebase to an array, then use that array in a flatlist to render the posts, but nothing is showing up. I would love some help.
Code
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TextInput, ScrollView, TouchableHighlight, Button, FlatList } from 'react-native';
import { Font } from 'expo';
import * as firebase from 'firebase';
const firebaseConfig = {
apiKey: "API_KEY",
authDomain: "candidtwo.firebaseapp.com",
databaseURL: "https://candidtwo.firebaseio.com",
storageBucket: "candidtwo.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
var fontLoaded = false;
var ref = firebase.database().ref('posts');
var newPostRef = ref.push();
var postWidth = 350;
export default class App extends React.Component {
state = {
fontLoaded: false,
};
componentDidMount() {
Expo.Font.loadAsync({
'JosefinSans-Regular.ttf': require('./JosefinSans-Regular.ttf'),
});
}
constructor(props) {
super(props);
this.state = { postInput: ""}
}
getItems() {
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push(childs.val());
});
});
return items;
}
renderItem({ items, index }) {
return <View>
<View style={{width: parseInt(this.state.postWidth), height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
{toString(reverse(items))}
</Text>
</View>
<View style={{width: parseInt(this.state.postWidth), height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
</View>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
</View>;
}
render() {
return (
<View style={styles.container}>
<View style={styles.button}>
<View style={{width: 1, height: 30, backgroundColor: '#e8e8e8'}} />
<Button
onPress={() => this.setState({ fontLoaded: true })}
title="Press Me To Load the App After 15 Seconds!"
color="#fe8200"
accessibilityLabel="Get started anonymously!"
/>
</View>
{this.state.fontLoaded ? (
<View style={styles.container}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Whats on your mind? Create a post!
</Text>
<TextInput
style={{height:40, width: 320, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postInput)=>this.setState({postInput})}
value={this.state.postInput}
/>
<Button
style={{justifyContent: 'center'}}
onPress={() => {
newPostRef.set({ content:this.state.postInput });
this.setState({ postInput: "Your post was succsesfully uploaded! :)" })
}}
title=" + "
color="#fe8200"
/>
<ScrollView>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Adjust the size of posts:
</Text>
<TextInput
style={{height:40, width: 100, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postWidth)=>this.setState({postWidth})}
value={this.state.postWidth}
/>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
<View style={{width: parseInt(this.state.postWidth), height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}} >
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
Why do android phones have higher inital quality than apple phones, but apple phones have a more consistent amount of quality throughout their years?
</Text>
</View>
<View style={{width: parseInt(this.state.postWidth), height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
3
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
1
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
8
</Text>
</View>
<FlatList
data={this.getItems}
renderItem={this.renderItem}
/>
</ScrollView>
</View>) : (null) }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 8,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
button: {
flex: 1,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
});
Picture of firebase database
id have getItems() in your componentWillMount method, and have it set a state ( Such as "firebaseItems" ) or such. Then in your FlatList have your data equal {this.state.firebaseItems}. This will force a re-render once you receive your information. EG
componentWillMount(){
this.getItems();
}
getItems(){
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push(childs.val());
});
}).then(() => {
this.setState({firebaseItems: items});
});
}
then later
<FlatList data = {this.state.firebaseItems}.../>

Content of a variable is [object Undefined]

Problem
I am creating a simple app using React Native and firebase where users can post to the web and see what other people have posted. You can upload things to the servers but when you try and render the posts using a flatlist, the posts say [object Undefined] instead of what is on the server. I would love help fixing this.
Code
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TextInput, ScrollView, TouchableHighlight, Button, FlatList } from 'react-native';
import { Font } from 'expo';
import * as firebase from 'firebase';
const firebaseConfig = {
apiKey: "API-key",
authDomain: "candidtwo.firebaseapp.com",
databaseURL: "https://candidtwo.firebaseio.com",
storageBucket: "candidtwo.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
var fontLoaded = false;
var ref = firebase.database().ref('posts');
var newPostRef = ref.push();
var postWidth = 350;
export default class App extends React.Component {
state = {
fontLoaded: false,
};
componentDidMount() {
Expo.Font.loadAsync({
'JosefinSans-Regular.ttf': require('./JosefinSans-Regular.ttf'),
});
}
constructor(props) {
super(props);
this.state = { postInput: ""}
}
componentWillMount(){
this.getItems();
}
getItems(){
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push(child.val());
});
}).then(() => {
this.setState({firebaseItems: items});
});
}
renderItem({ items, index }) {
return <View>
<View style={{width: 360, height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
{/*{toString(reverse(items))}*/} {toString(items)}
</Text>
</View>
<View style={{width:360, height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
</View>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
</View>;
}
render() {
return (
<View style={styles.container}>
<View style={styles.button}>
<View style={{width: 1, height: 30, backgroundColor: '#e8e8e8'}} />
<Button
onPress={() => this.setState({ fontLoaded: true })}
title="Get started anonymously!"
color="#fe8200"
accessibilityLabel="Run the app"
/>
</View>
{this.state.fontLoaded ? (
<View style={styles.container}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Whats on your mind? Create a post!
</Text>
<TextInput
style={{height:40, width: 320, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postInput)=>this.setState({postInput})}
value={this.state.postInput}
/>
<Button
style={{justifyContent: 'center'}}
onPress={() => {
newPostRef.set({ content:this.state.postInput });
this.setState({ postInput: "Your post was succsesfully uploaded! :)" })
}}
title=" + "
color="#fe8200"
/>
<ScrollView>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Adjust the size of posts:
</Text>
<TextInput
style={{height:40, width: 100, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postWidth)=>this.setState({postWidth})}
value={this.state.postWidth}
/>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
<View style={{width: parseInt(this.state.postWidth), height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}} >
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
Why do android phones have higher inital quality than apple phones, but apple phones have a more consistent amount of quality throughout their years?
</Text>
</View>
<View style={{width: parseInt(this.state.postWidth), height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
3
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
1
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
8
</Text>
</View>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
<FlatList
data = {this.state.firebaseItems}
renderItem={this.renderItem}
/>
</ScrollView>
</View>) : (null) }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 8,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
button: {
flex: 1,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
});
Firebase database layout
posts:
ipaurfiauerspfna(random example key):
content: "hello world"
apiergnfpiarngaenig:
content: "test"
helpful warning message[![warning][2]][2] VirtualizedList: missing keys for items, make sure to specify a random key property on every item or provide a custom keyExtractor.
You are trying to pull firebaseItems from state before you have set it (due to the delay in query response), so this will throw an error. To fix this, declare it is a state variable in your constructor. EG
export default class App extends React.Component {
...
constructor(props) {
super(props);
this.state = {
postInput: "",
firebaseItems: [],
}
}
Looks like you haven't set some variables yet, you are going to want to extend your current code of:
state = {
fontLoaded: false,
};
to
state = {
postInput: "", // Or some other default
fontLoaded: false,
};

Categories