I'm trying to download user profiles from firebase and use them in a component. I'm having trouble with the async firebase function and useState. In the code below "profiles" repeatedly gets concatenated but it doesn't seem to update the "cards" prop in the Swiper component which still gets an empty array.
import * as React from 'react';
import Swiper from 'react-native-deck-swiper'
import { Card } from '../components/Card'
import { View } from '../components/Themed';
import firebaseSDK from '../database/firebase'
export default function HomeScreen() {
const [profiles,setProfiles] = React.useState([])
firebaseSDK.db
.ref('userProfile')
.once('value')
.then((snapshot)=>{
//this line prints the profiles correctly
console.log("snapshot Val profiles : " + JSON.stringify(Object.values(snapshot.val())))
setProfiles(prevState => prevState.concat(Object.values(snapshot.val())))
})
return (
<View style={styles.container}>
<Swiper
cards={profiles}
renderCard={Card}
/>
}
using this code I get
TypeError: undefined is not an object (evaluating 'cards.length')
Even though the console log shows "profiles" is continuously growing bigger as it gets repeatedly concatenated. What's the process to access the data correctly?
EDIT:
some more details about the code
the data I'm downloading looks like this :
{
"id1":{
avatar: "https://placebear.com/200/300",
displayName: 'Fakeman Fakeaccount',
AboutMe: '16 miles away',
uid:1234
},
"id2":{
avatar: "https://placebear.com/200/300",
displayName: 'Joanna, 19',
AboutMe: '2 miles away',
uid:1234
},
"id3":{
avatar: "https://placebear.com/200/300",
displayName: 'Charlie, 32',
AboutMe: '24 miles away',
uid:1234
},
}
cards takes an array of objects, which is why I initialized useState with an "[]" and I ran Object.values on snapshot.val() to turn it into an array.
The Card component:
export const Card = ({ avatar, displayName, AboutMe, uid }) => (
<Tile
// imageSrc={avatar}
imageSrc={{uri:avatar}}
imageContainerStyle={styles.imageContainer}
activeOpacity={0.9}
title={displayName}
titleStyle={styles.title}
caption={AboutMe}
captionStyle={styles.caption}
containerStyle={styles.container}
key={uid}
featured
/>
)
Swiper takes an array of data (cards prop) and uses it to populate multiple Card components (renderCard prop)
EDIT 2:
Thanks to @DougStevenson the download problem is solved (update state inside a useEffect block)
const [profiles,setProfiles] = React.useState([
{
avatar: "https://placebear.com/200/300",
displayName: 'Placeholder',
AboutMe: 'Im not real',
uid:"000000000000000000"
},
])
React.useEffect(() => {
firebaseSDK.db
.ref('userProfile')
.once('value', (snapshot)=>{
//returns an array [{...},{...},{...},...]
console.log(JSON.stringify(Object.values(snapshot.val())))
setProfiles(Object.values(snapshot.val()))
})
However now setProfiles truncates the data into a single element array. I think this is because of how I defined the initial state and because I'm using a TypeScript template it's finicky about definitions?
EDIT 3 :
Ok so it turns out it was the Swiper component which was messing up. Swiper is a stack of Views, it initialized with an array of length 1 which means it created 1 View in the stack. When I updated the cards prop it only updated the 1 View in the stack and didn't add more Views.