Home > OS >  ReactJS need to get some values from promise
ReactJS need to get some values from promise

Time:09-18

In Firebase I have two Documents. one is "users" and "posts".

Inside posts, I have added an id equal to the "users" collection id.

What I'm trying to achieve is when I'm getting posts I need to get post-added user data.

I'm getting all the posts but I cannot get related user data. Can anyone help me do this?


import {
  collection,
  query,
  onSnapshot,
  orderBy,
  doc,
  getDoc,
} from "firebase/firestore";

import { db } from "../../FireBaseConfig";

export default function Home() {
  const [posts, setPosts] = useState();

  const getPostUser = async (userID) => {
    try {
      const userQuery = doc(db, "users", userID);

      const userRef = await getDoc(userQuery);

      const userData = userRef.data();

      return userData;
    } catch (err) {
      console.log(err);
    }
  };

  useEffect(() => {
    const getPosts = async () => {
      try {
        const q = query(collection(db, "posts"), orderBy("statusDate", "desc"));

        const unsubscribe = onSnapshot(q, (querySnapshot) => {
          let posts_arr = [];
          let adsfadsfad = "";
          querySnapshot.forEach(async (item, index, array) => {
            getPostUser(item.data().id)
              .then((res) => {
                adsfadsfad.push(res);
              })
              .catch((err) => {
                console.log(err);
              });

            console.log(adsfadsfad);

            posts_arr.push(
              <div className="home__posts--post" key={item.id}>
                <div className="home__posts--post-user flex items-center">
                  {/* <img
                      src={abc["avatar"]}
                      alt={abc["avatar"]}
                      className="w-[50px] h-[50px] rounded-full"
                    />
                    <h4>{abc["avatar"]}</h4> */}
                  {/* {asdasd} */}
                </div>
                <div>
                  {item.data().statusImage && (
                    <img
                      src={item.data().statusImage}
                      alt={item.data().status}
                    />
                  )}
                </div>
              </div>
            );
          });
          setPosts(posts_arr);
        });
      } catch (err) {
        console.log(err);
      }
    };

    getPosts();
  }, []);

  return (
    <div className="home p-4 max-w-screen-sm mx-auto">
      <div className="home__posts">{posts}</div>
    </div>
  );
}

CodePudding user response:

Your code also queries for user data for every post. In case all the posts returned by first query are posted by same person, it'll be redundant. Also the getDoc() (getPostUser()) returns a Promise so you need to handle that as well. Try refactoring the code as shown below:

useEffect(() => {
  const getPosts = async () => {
    const q = query(collection(db, "posts"), orderBy("statusDate", "desc"));

    const unsubscribe = onSnapshot(q, async (querySnapshot) => {
      const posts = querySnapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
      }));

      // Get an array of unique user IDs from all posts
      const userIds = [...new Set(posts.map((post) => post.userId))];

      // Fetch documents of those users only
      const userPromises = userIds.map((userId) =>
        getDoc(doc(db, "users", userId))
      );

      const userDocs = await Promise.all(userPromises);

      // Record<string, UserDocumenData>
      const users = userDocs.reduce((acc, userDoc) => {
        acc[userDoc.id] = userDoc.data();
        return acc;
      }, {});

      // use "posts" array and "users" object to render your UI
      // You can get user info as shown below
      // const postUser = users[posts[0].userId]
    });
  };

  getPosts();
}, []);

If you want to, you can also additionally remove some userId from the second query in case their data has been fetched already.

  • Related