Home > Blockchain >  React component doesn't render unless I refresh & duplicate render
React component doesn't render unless I refresh & duplicate render

Time:11-21

I've been working on React/Redux app with firestore database

In my app I have simple POST request sent when the user send a message in the input field and the data the user enters supposed to render in the same page without the need to refresh but I do still need to refresh even without deps in my useEffect!

Here's my code :

  • Post component
        {posts.length > 0 &&         
          [...posts].map(({ id, data: { message, name, job, avatarUrl } }) => (
            <Post
              key={id}
              name={name}
              job={job}
              message={message}
              avatarUrl={avatarUrl}
            />
          ))}

However I also encounter a weird behavior after I refresh which is the components are rendered twice!Although my database be containing only one unique data for each messageThe react app renders it twice ( The querySnapshot from the database being added to the state arrayposts twice

  • useEffect
useEffect(() => {
    querySnapshot();
     });
  }, []);

  • Database query:

      const q = query(
        collection(db, "posts"),
        where("type", "==", "post"),
        orderBy("postDate", "desc")
      );
    
  • Retrieving the data :

  const [input, setInput] = useState("");
  const [posts, setPosts] = useState([]);
  const [nextId, setNextId] = useState("0");
  const addPost = (e) => {
    e.preventDefault();

    const docData = {
      name: "mo",
      job: "zoo",
      message: input,
      avatarUrl: "https://",
      postDate: firebase.firestore.FieldValue.serverTimestamp(),
      type: "post",
    };

    setDoc(doc(db, "posts", nextId.toString()), docData);
    setNextId(parseInt(nextId)   1);
    setInput("");
  };

  async function querySnapshot() {
    const querySnapshot = await getDocs(q);
    console.log(querySnapshot.docs[0].data().message);
    setNextId(querySnapshot.docs.length)
    querySnapshot.docs.forEach((doc) => {
      let data = {
        id: doc.id,
        data: doc.data(),
      };
      if (data && !posts.includes(data.id)) {
        setPosts((current) => [...current, data]);
        console.log("psts now", posts);
      }
    });
  }

I tried to use the JavaScript Set by creating useState(new Set()) but the same problem occurred of duplicate elements

I also tried to change deps of useEffect to render when the posts state array changes still not rendering untill I refresh

CodePudding user response:

The duplication reason would be caused by setPosts(), I have updated the code as below, try to avoid setting the value inside the loop.

  async function querySnapshot() {
    const querySnapshot = await getDocs(q);
    setNextId(querySnapshot.docs.length)
    const data = querySnapshot.docs.map((doc)=>{
      return {id:doc.id, data: doc.data()}
    })

    setPosts((current) => [...current, data])
  }
  • Related