I'm developing an app which has to fetch new orders from the Firestore database, I used componentDidMount
to refresh the screen every 10 seconds and launch the fetchNewOrders
function, if new orders are available, the function should push that object into the state array newOrder
, and display the orders in the FlatList below. When I start the code it returns the error TypeError: undefined is not an object (evaluating 'item.id')
, I also wrote the example of an array I'm fetching from the database.
Screen
export default class Received extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
newOrder: [],
};
}
async componentDidMount() {
this.updateTimer = setInterval(() => {
this.fetchNewOrders();
}, 10000);
}
fetchNewOrders = async () => {
const querySnapshot = await getDocs(collection(db, path));
if(querySnapshot.length !== 0) {
querySnapshot.forEach((doc) => {
let array = this.state.newOrder;
const data = doc.data().order;
data.map(({obj, id}) => {
const filter = array.find(c => c.id === id);
if (filter == undefined) {
array.push(obj)
this.setState({ newOrder: array })
}
})
})
}
}
render() {
return (
<View>
<FlatList
data={this.state.newOrder}
keyExtractor={item => item.id}
renderItem={({ item }) => {
return (
<TouchableOpacity>
<Text>{item.serviceRequested}</Text>
<View>
<Tex>${item.total}</Text>
</View>
</TouchableOpacity>
)
}}
/>
</View>
)
}
}
data (new order)
Array [
Object {
"date": "Mon Feb 28 2022 11:24:14 GMT-0500 (EST)",
"id": 0.9436716663143794,
"instructions": "",
"order": Array [
/////////////
],
"paymentType": "Cash",
"serviceRequested": "Delivery",
"total": 10.4,
},
]
CodePudding user response:
setState is an async function that schedules a render with new state. It should only be called once per render, not in a loop.
const append = [];
querySnapshot.forEach((doc) => {
const data = doc.data().order;
// Is there bad data without ids?
data.filter(c => c.id && !this.state.newOrder.some(no => no.id === c.id))
.forEach((d) => append.push(d));
});
// Create the new state, then set it once.
this.setState({ newOrder: [...this.state.newOrder, ...append]});
CodePudding user response:
I would suggest filtering your data (this.state.newOrder) first. This would make it so that you only display items that have ids.
Suggested Change:
<FlatList
data={this.state.newOrder.filter((order)=>order.id)}
keyExtractor={item => item.id}
renderItem={({ item }) => {
return (
<TouchableOpacity>
<Text>{item.serviceRequested}</Text>
<View>
<Tex>${item.total}</Text>
</View>
</TouchableOpacity>
)
}}
/>
Above is code to fix this issue as described, but I would suggest that you make sure the Firestore only sends data that has id's if possible. Obviously, this may be out of your hands, but I would make sure that the Firestore is giving you reliable data, as it could cause more problems down the road.