Home > OS >  Display all posts from database
Display all posts from database

Time:05-09

I have a Firestore collection, schemed as follows:

posts{
    uid{
        userPosts{
            postID{
                creation:
                postText:
            } 
        }
    }
}

I want to display all of the posts, so I've made the corresponding queries and saved them in posts - an array of all the posts that I later iterate through.

The problem with the way I do it is that it keeps adding the same posts every render. So I've tried to set the array each time, but that way the code never passes through these posts && posts.length > 0 condition.

I'm really new to RN and JS in general, but what I was expecting is

Nothing to show here

at first, and then the list of posts.

The complete component:

import { Text, Pressable, FlatList, SafeAreaView } from "react-native";
import { globalStyles } from "../../styles/global";
import React, { useState, useEffect } from "react";
import { db } from "../../../firebase";
import Post from "../../API/Post";
import { collection, getDocs } from "firebase/firestore";

const FeedScreen = ({ navigation }) => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    const getPostData = async () => {
      setPosts([]); // ---> Without this line the posts keeps adding each render
      const q = collection(db, "posts");
      const docSnap = await getDocs(q);
      docSnap.docs.map(async (item) => {
        const tmp = collection(db, "posts", item.id, "userPosts");
        const tmpSnap = await getDocs(tmp);
        tmpSnap.docs.map(async (element) => {
          setPosts((prev) => {
            prev.push(element.data());
            return prev;
          });
        });
      });
    };

    getPostData().catch(console.error);
    return;
  }, []);

  return (
    <SafeAreaView style={globalStyles.global}>
      {posts && posts.length > 0 ? (
        <FlatList
          data={posts}
          renderItem={({ item }) => (
            <Post
              post={item}
              navigation={navigation}
              style={globalStyles.list_of_posts}
            />
          )}
          keyExtractor={(item, index) => index.toString()}
        />
      ) : (
        <Text>Nothing to show here</Text>
      )}

      <Pressable
        title="edit"
        onPress={() => {
          navigation.navigate("CreatePost", { navigation });
        }}
        style={globalStyles.plus_btn}
      >
        <Text style={globalStyles.plus_btn_text}> </Text>
      </Pressable>
    </SafeAreaView>
  );
};

export default FeedScreen;

As said, I'm new to this so I'd love an explanation of what actually happens and how to do it properly.

CodePudding user response:

I think the prev value of setPosts will always be [] since it does not immediately update if you call it. A standard way to do it is to call setPosts at the end of your function. Can you try this one?

useEffect(() => {
    const getPostData = async () => {
      const q = collection(db, "posts");
      const docSnap = await getDocs(q);
      const promises = docSnap.docs.map(async (item) => {
        const tmp = collection(db, "posts", item.id, "userPosts");
        const tmpSnap = await getDocs(tmp);
        return tmpSnap.docs.map((element) => element.data());
      });
      const arrayOfPosts = await Promise.all(promises);
      let newPosts = [];
      arrayOfPosts.forEach((posts) => {
        newPosts = [...newPosts, ...posts];
      });
      setPosts(newPosts);
    };

    getPostData().catch(console.error);
    return;
  }, []);
  • Related