简体   繁体   中英

Async/await in useEffect hook doesn't await a function

As the title says. I'm using firestore for my chat service. I'm attempting to set up a way to filter out messages when the firestore updates

  const users = useSelector((state) => state.assignUser);

  const [messages, setMessages] = useState([]);

  const chatID = 'KfM3GNxeVATi6sNFFUEG'

  function getIDs(messageObj){
    return messageObj.map(message => message._id)
  }

  useEffect(() => {
    const messagesArray = []

    db.collection('messages').doc(chatID).collection('messages').get().then(snapshot => {
      snapshot.forEach(doc => messagesArray.push(doc.data()))
      setMessages(messagesArray)

      async function fetchMessages(){
        const messageIDs = await getIDs(messages)
        db.collection('messages').doc(chatID).collection('messages').onSnapshot(doc => {
          doc.forEach((document) => {
            if (messageIDs.indexOf(document.data()._id !== -1)) console.log('the is is ', messageIDs.indexOf(document.data()._id))
            else console.log('notfoundssw')
          })
        })
      }
      fetchMessages()
    })
  }, [])

The await doesn't await the getIDs function and the log of messageIDs.indexOf(document.data()._id) is -1 for every entry. I can't figure out why the async/await missbehaves

your messagesIDs variable depends on messages state update, which does not happen sync. Based on your code structure you would have to break in 2 useEffects . The first one that updates messages on mount and the second that listens to messages updates:

  useEffect(() => {
    const messagesArray = []

    db.collection('messages').doc(chatID).collection('messages').get().then(snapshot => {
      snapshot.forEach(doc => messagesArray.push(doc.data()))
      setMessages(messagesArray)
    })
  }, [])


  useEffect(() => {
    // check if messages is not empty
    if(!messages.length) return

    const messageIDs = getIDs(messages) // your getIDs is not async, so no need to await
    db.collection('messages').doc(chatID).collection('messages').onSnapshot(doc => {
      doc.forEach((document) => {
        if (messageIDs.indexOf(document.data()._id) !== -1) {
          console.log('the is is ', messageIDs.indexOf(document.data()._id))
        } else {
          console.log('notfoundssw')
        }
      })
    })
}, [messages])

Not sure I can fully understand how you're getting data, but setting state is actually asynchronous so you cannot guarantee all your state data is updated by the time you execute map .

I would break up your useEffect into two different ones.

The second one which will contain the fetchMessages call should use 'messages' as part of its dependency array, ie it will execute once your 'messages' state has been updated.

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