Search code examples
reactjsfirebasereact-nativegoogle-cloud-firestorereact-component

React Native: Duplicate items in component state


I have a two screens in a StackNavigator, one with a FlatList that displays data retrieved from Firestore, and another to add a new data to the database. After returning from the second screen in the stack via navigation.goBack(), the new item should be appended to the list. Instead, the entire state with the new item is being appended to the old state. The database data contains no duplicates and upon refresh, the list contains the correct elements.

I can't tell if I'm misunderstanding the component lifecycle or the query itself so I would appreciate any help.

export default class Main extends React.Component {

state = { chatData:[] }


componentDidMount = () => {
  // Make call to Cloud Firestore
  // for the current user, retrieve the chat document associated with each element in the chats id array
  let user = firebase.auth().currentUser;
  firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
    doc.data().chats.map((element) => {
      firestore().collection("chats").doc(element).onSnapshot((doc) => {
        this.setState({chatData: [...this.state.chatData, 
          {id: element, subject: doc.data().subject, course: doc.data().course}]})
      })
    });
  })
}

enter image description here enter image description here

state after adding a course and returning to the list screen (duplicate element)


Solution

  • Here is my eventual solution. I'm using react-navigation addListener to call the firestore API whenever the first screen is switched to and clearing the state when the second screen is navigated to. I also switched from onSnapshot() to get() for my firestore calls.

    class Main extends React.Component {
    
      state = { currentUser: null, chatData:[]}
    
    
      componentDidMount = () => {
        console.log('A - component did mount')
        // definitely works
        this.willFocusSubscription = this.props.navigation.addListener(
          'willFocus',
          payload => {
            console.log('A- focus')
            this.readCourseData()
        }) 
        this.willBlurSubscription = this.props.navigation.addListener(
          'willBlur',
          payload => {
            console.log('A- blur')
            this.setState({chatData: []})
          })
      }
    
      componentWillUnmount() {
        console.log('A - component will unmount')
        this.willFocusSubscription.remove();
        this.willBlurSubscription.remove();
        // Remove the event listener
      }
    
    
      readCourseData = () => {
        // Make call to Cloud Firestore
        // for the current user, retrieve the chat document associated with each element in the chats array
        let user = firebase.auth().currentUser;
        firestore().collection("users").doc(user.uid).get().then((doc) => {
          doc.data().chats.map((element) => {
            firestore().collection("chats").doc(element).get().then((doc) => {
              let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
              let uniqueArray = [...new Set(newArray)]
              this.setState({
                  chatData: uniqueArray
              })
            })
          });
        })
      }