React Native: дублирующиеся элементы в состоянии компонента - PullRequest
1 голос
/ 28 января 2020

У меня есть два экрана в StackNavigator, один с FlatList, который отображает данные, извлеченные из Firestore, и другой для добавления новых данных в базу данных. После возврата со второго экрана в стеке с помощью navigation.goBack () новый элемент должен быть добавлен в список. Вместо этого все состояние с новым элементом добавляется к старому состоянию. Данные базы данных не содержат дубликатов, и после ссылки sh список содержит правильные элементы.

Я не могу сказать, неправильно ли я понимаю жизненный цикл компонента или сам запрос, поэтому буду признателен за любую помощь.

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

состояние после добавления курса и возврата к экрану списка (дубликат элемента)

Ответы [ 3 ]

0 голосов
/ 29 января 2020

Попробуйте создать новый массив с уникальными значениями и присвойте ему значение chatData

componentDidMount = () => {
    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) => {
                /**
                 * create a new array with unique values
                 */
                let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
                let uniqueArray = [...new Set(newArray)]
                this.setState({
                    chatData: uniqueArray
                })
            })
        });
    })
}

Надеюсь, это вам поможет. Не стесняйтесь сомнений.

0 голосов
/ 29 января 2020

Вот мое окончательное решение. Я использую реагирующий на навигацию addListener для вызова API Firestore всякий раз, когда переключается первый экран, и очищаю состояние при переходе ко второму экрану. Я также переключился с onSnapshot () на get () для своих вызовов в пожарном депо.

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
          })
        })
      });
    })
  }
0 голосов
/ 29 января 2020

При установке состояния попробуйте использовать функцию обратного вызова prevState. Примерно так:

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) => {
        // We use the parameter of the first argument of setState - prevState
        this.setState(prevState => ({chatData: [...prevState.chatData, 
          {id: element, subject: doc.data().subject, course: doc.data().course}]}))
      })
    });
  })
}

Поскольку вы хотите распространить состояние, которое было там ранее, как аккумулятор, новыми данными, которые вы получаете от firestore. Если вы сделаете это с this.state, вы добавите его снова, поскольку оно касается данных, которые уже находятся в состоянии и поэтому повторяются / дублируются. Дайте мне знать, если это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...