简体   繁体   中英

React Native firebase function doesn't fetch correctly under useEffect

I am using react native and firebase firestore on a project.

I want to fetch some data of the post in the post screen, and when I try to fetch it, it doesn't work from the first try. I'm using useEffect to avoid infinite loops and I added a console.log to see what really happens.

What should happen: the firebase.firestore()...get() should retrieve the data of the post from firestore in an object inside an array. However, when using useEffect, the first time it's unsuccessful. I set a console.log after the whole fetch to check if the arr.length !== 0 and I can clearly see that arr.length === 0.

However, here is the weird thing, If I let the useEffect run indefinitely, from the 2nd try on it retrieves the data good. Any ideas on how things can be solved?

const [post, setPost] = useState([]);


        useEffect(() => {

            
    
            firebase.firestore()
            .collection("allPosts")
            .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
            .get()
            .then((snapshot) => {
                let data = snapshot.docs.map(doc => {
                    const data = doc.data();
                    const id = doc.id;
                    return { id, ...data }
                })
                setPost(data)
            })

            if (post.length !== 0) {
                console.log('Worked')
            } else {
                console.log('Empty')

                
            } 
                            
    
        }, [])

EDIT: const [post, setPost] = useState(null);

useEffect(() => {

            
    
            // 1
            firebase.firestore()
            .collection("allPosts")
            .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
            .get()
            .then((snapshot) => {

              //2
                let data = snapshot.docs.map(doc => {
                    const data = doc.data();
                    const id = doc.id;
                    return { id, ...data }

                
                })
                setPost(data)

                 //3
            if (data.length !== 0) {
                console.log('Worked')
                
            } else {
                console.log('Empty')

                
            } 

            console.log(post)
            })
            

           
                            
    
        }, [])

The console log of data.length returns worked, the console log of post(last) returns null. That's what I don't understand, why?

The code is behaving as it should. You should move the console.log into the then . The wait it's now it will be executed in this order:

const [post, setPost] = useState([]);

useEffect(() => {
  // 1
  firebase.firestore()
    .collection("allPosts")
    .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
    .get()
    .then((snapshot) => {
      //3
      let data = snapshot.docs.map(doc => {
        const data = doc.data();
        const id = doc.id;
        return {
          id,
          ...data
        }
      })
      setPost(data)
    })

  //2
  if (post.length !== 0) {
    console.log('Worked')
  } else {
    console.log('Empty')
  }
}, [])

That is the reason you don't see any that in the first try. The console.log is executed before the async data is loaded from firestore.

Change your code to this to make it work as expected:

const [post, setPost] = useState([]);
useEffect(() => {
  // 1
  firebase.firestore()
    .collection("allPosts")
    .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
    .get()
    .then((snapshot) => {
      //2
      let data = snapshot.docs.map(doc => {
        const data = doc.data();
        const id = doc.id;
        return {
          id,
          ...data
        }
      })
      setPost(data)

      //3
      if (data.length !== 0) {
        console.log('Worked')
      } else {
        console.log('Empty')
      }
    })
}, [])

You could also use another useEffect to log the changed data:

  useEffect(()=>{
          if (post.length !== 0) {
                console.log('Worked')
            } else {
                console.log('Empty')

                
            } 
        },[post])

Or just log it directly in the render function.

EDIT:

const [post, setPost] = useState(null);
useEffect(() => {
  // 1
  firebase.firestore()
    .collection("allPosts")
    .where(firebase.firestore.FieldPath.documentId(), '==', props.route.params.postId)
    .get()
    .then((snapshot) => {
      //2
      let data = snapshot.docs.map(doc => {
        const data = doc.data();
        const id = doc.id;
        return {
          id,
          ...data
        }
      })
      setPost(data)
      //3
      if (data.length !== 0) {
        console.log('Worked')

      } else {
        console.log('Empty')
      }

      console.log(post)
    })
}, [])

The console log of data.length returns worked, the console log of post(last) returns null. That's what I don't understand, why?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM