'How can I avoid rendering the "no profile" card where there are profiles?

I have an issue. I have a dating similar to tinder and when there is no more profiles the following card is displayed :

enter image description here

My problem is that when I open the app, this card is rendered for 2 of 3 seconds before the profiles. I tried to have a loading symbol, when fetchcards is done, this problem persists :

The following is my code :

    const fetchCards = async () => {


        setloading(true);

        const passes = await getDocs(collection(db, "user", user.uid, "passes")).then(
          (snapshot) => snapshot.docs.map((doc) => doc.id)
          
        );

        const swipes = await getDocs(collection(db, "user", user.uid, "swipes")).then(
          (snapshot) => snapshot.docs.map((doc) => doc.id)
        );

        const passedUserIds = passes.length > 0 ? passes : ["test"]; 
        const swipedUserIds = swipes.length > 0 ? swipes : ["test"]; 
      
      const sex = await getDocs(collection(db, "femmes")).then(
            (snapshot) => snapshot.docs.map((doc) => doc.id)
           );

 
      const sexUserIds = sex.length > 0 ? sex : ["test"]; 

       //console.log('sex : ' + sex );
      // console.log('sexUserIds : ' + sexUserIds );
      // console.log('user.uid : ' + user.uid );

     artie = sexUserIds.includes(user.uid);

     //console.log(' artie  : ' +  artie );
       
     let difference = sexUserIds.filter(x => !passedUserIds.includes(x));

     const difference2 = difference.filter(x => !swipedUserIds.includes(x));

  
//console.log(' similitude entre sexUserIds et swipedUserIds : ' + sexUserIds.filter(e => swipedUserIds.includes(e)));
//console.log(' similitude final : ' + sexUserIds.filter(e => passedUserIds.includes(e)));

    if (artie == true) {

// femmme
      unsub = onSnapshot(query(collection(db, "user"), where("id", "not-in", [...passedUserIds, ...swipedUserIds, ...sexUserIds]) 

        
      ), 
      
      (snapshot) => {
        setProfiles(
          snapshot.docs
          .filter((doc) => doc.id !== user.uid)
          .map((doc) => ({
            id: doc.id,
            ...doc.data(),
          }))
        );
      });

    } else {

      // homme

      unsub = onSnapshot(query(collection(db, "user"), where("id", "in", [...difference2]) 

        
      ), 
      
      (snapshot) => {
        setProfiles(
          snapshot.docs
          .filter((doc) => doc.id !== user.uid)
          .map((doc) => ({
            id: doc.id,
            ...doc.data(),
          }))
        );
      });
   

    }

    setloading(false);
      
      };

      fetchCards();
      return unsub;
    }, [db]);

 return (
    
    <SafeAreaView style={tw("flex-1 top-10")}>
      {/*Header*/}
      
      <View style={tw("flex-row justify-between items-center ")}>

      <TouchableOpacity onPress={logout}>
        <Image style={tw("relative rounded-full h-16 w-16 mr-4")} source={{ uri: profilepic }}/>
      </TouchableOpacity>

      <TouchableOpacity onPress={() => navigation.navigate("Modal")}>
        <Image style={tw("h-14 w-14")} source={require("../logo.png")}/>
      </TouchableOpacity>

      <Button onPress={() => navigation.navigate("Chat")} title="Messages" color="#e71e24" style={tw("absolute left-7 top-3")}/>


     

      </View>



   

      {/*End of Header*/}

      {/* Cards */}

      <View style={tw("flex-1 -mt-6")}>

      <Swiper 
      ref={swipeRef}
      containerStyle={{ backgroundColor: "transparent" }}
      cards={profiles}
      stackSize={5}
      cardIndex={0}
      animateCardOpacity
      verticalSwipe={true}
      onSwipedLeft={(cardIndex) => {
        console.log('SWIPE PASS');
        swipeLeft(cardIndex);

      }}
      onSwipedRight={(cardIndex) => {
        console.log('SWIPE MATCH');
        swipeRight(cardIndex);

      }}
      onSwipedTop={(cardIndex) => {
        console.log('FLAG');
        swipeTop(cardIndex);

      }}

      backgroundColor={"#4FD0E9"}
      overlayLabels={{
        left: {
          title: "NOPE",
          style: {
            label: {
              textAlign: "right",
              color: "red",
            },
          },
        },

        right: {
          title: "MATCH",
          style: {
            label: {
            
              color: "#4DED30",
            },
          },
        },

        top: {
          title: "FLAG",
          style: {
            label: {
            
              color: "#4DED30",
            },
          },
        },
      

      }}
      renderCard={(card) => card ? (
      
        <View key={card.id} style={tw("relative bg-white h-3/4 rounded-xl")}>
        <Image 
        style={tw("absolute top-0 h-full w-full rounded-xl")} 
        
        source={{ uri: card.photoURL}}
        
        />

        <View style={[tw("absolute bottom-0 bg-white w-full flex-row justify-between items-center h-20 px-6 py-2 rounded-b-xl"), styles.cardShadow,]}>
        <View>
          
          <Text style={tw("text-xl font-bold")}>
            {card.displayName}
          </Text>
          <Text>{card.job}</Text>
          
      </View>
      <Text style={tw("text-2xl font-bold")}> {card.age}</Text>

      </View>
      </View>

      ) : (

        <View
        style={[
          tw("relative bg-white h-3/4 rounded-xl justify-center items-center"
          ),
          styles.cardShadow,
        ]}
        >
          <Text style={tw("font-bold pb-5")}>Plus de profils</Text>

          <Image
          style={tw('h-20 w-20 rounded-full')}
          source={{uri: "https://links.papareact.com/6gb" }}
          
          />

        </View>
      )}
      />

       <View style={styles.row}>
    <View>
      {getBannerAd()}
    </View>
    <StatusBar style="auto" />
  </View>
      
      </View>

      <View style={tw("flex flex-row justify-evenly bottom-10")}>
        <TouchableOpacity 
        onPress={()=> swipeRef.current.swipeLeft()}
        style={tw("items-center justify-center rounded-full w-16 h-16 bg-red-200")}>
        <Entypo name="cross" size={24} color="red"/>
        </TouchableOpacity>

        <TouchableOpacity 
        onPress={()=> swipeRef.current.swipeTop()}
        style={tw("items-center justify-center rounded-full w-16 h-16 bg-purple-200")}>
        <Entypo name="warning" size={24} color="red"/>
        </TouchableOpacity>

        <TouchableOpacity 
        onPress={()=> swipeRef.current.swipeRight()}
        style={tw("items-center justify-center rounded-full w-16 h-16 bg-green-200")}>
        <AntDesign name="heart" size={24} color="green"/>
        </TouchableOpacity>

    

      </View>

    </SafeAreaView>
  );


Solution 1:[1]

Since you are using a loading state, you could use an additional conditional in your render function and wait until the date is fetched before you decide which cards to show (the fetched cards or the “no cards” screen).


renderCard={(card) => {
        if(isLoading) {
            // return whatever
        } else if(card){
            return <View key={card.id} style={tw("relative bg-white h-3/4 rounded-xl")}>
            <Image 
            style={tw("absolute top-0 h-full w-full rounded-xl")} 
            
            source={{ uri: card.photoURL}}
            
            />

            <View style={[tw("absolute bottom-0 bg-white w-full flex-row justify-between items-center h-20 px-6 py-2 rounded-b-xl"), styles.cardShadow,]}>
            <View>
              
              <Text style={tw("text-xl font-bold")}>
                {card.displayName}
              </Text>
              <Text>{card.job}</Text>
              
          </View>
          <Text style={tw("text-2xl font-bold")}> {card.age}</Text>

          </View>
          </View>
        } else {
           return <View
            style={[
              tw("relative bg-white h-3/4 rounded-xl justify-center items-center"
              ),
              styles.cardShadow,
            ]}
            >
              <Text style={tw("font-bold pb-5")}>Plus de profils</Text>

              <Image
              style={tw('h-20 w-20 rounded-full')}
              source={{uri: "https://links.papareact.com/6gb" }}
              
              />

            </View>
          )}
        }
    }
                 

It might be suitable to just return null.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 David Scholz