Реакция: получить данные из базы данных и сохранить их, используя условие гонки setState - PullRequest
0 голосов
/ 08 июня 2018

Кажется, у меня какое-то состояние гонки с setState при чтении данных из Firebase.При загрузке компонента прослушиватель child_added вызывается столько раз, сколько записей клиента находится в таблице clients, но только последняя запись клиента фактически сохраняется в состоянии с использованием setState.Я знаю, что это связано с задержкой в ​​setState, где он работает только после окончания цикла, поэтому существует условие гонки с несколькими вызовами setState.Как это исправить, чтобы все записи клиента правильно сохранялись в this.state.clients?

class ClientsTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      clients: [],
    };
  }

  componentWillMount(){
      let clientsRef = fire.database().ref('clients').orderByKey().limitToLast(100);
      clientsRef.on('child_added', snapshot => {
        let client = snapshot.val();
        client.id = snapshot.key
        this.setState({ clients: [client].concat(this.state.clients) })
      })
  }
}

Ответы [ 2 ]

0 голосов
/ 02 мая 2019

Проблема в том, что вам нужно очистить ваши ссылки на Firebase, иначе это приведет к утечкам памяти.В React это обычно делается в componentWillUnmount .

. Используя ваш пример, вам нужно добавить следующее:

componentWillUnmount: function() {
  this.clientsRef.off();
}

Вам также необходимо изменить код в componentDidMount , поэтому вы используете this.clientsRef вместо использования локальной переменной.

Вы можете прочитать подробнееоб этом в блоге Firebase .

0 голосов
/ 09 июня 2018

Не должно быть никаких условий гонки, поскольку setState() ставит изменения в очередь при каждом вызове, в этом случае каждый снимок client, полученный в результате события child_added, включая существующие client и новые clientдобавлено.

Возможно, проблема в том, что ваш синтаксис для setState() может меняться / возвращаться this.state.clients каждый раз.Вместо этого попробуйте использовать spread syntax ... для добавления client объектов к this.state.clients и неизменного обновления / слияния this.state.

class ClientsTable extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      open: false,
      clients: []
    };
  }

  componentWillMount(){
    const clientsRef = fire.database().ref('clients').orderByKey().limitToLast(100);

    clientsRef.on('child_added', snapshot => {
      const client = { ...snapshot.val(), id: snapshot.key };

      this.setState({
        ...this.state,
        clients: [...this.state.clients, client]
      });
    });
  }
}

Используя личный проект Firebase, я смог получитькаждый элемент в эквиваленте this.state.clients и отображать их соответственно в componentDidMount или componentWillMount.Если вы хотите, вы можете создать фиктивный проект Firebase с фиктивными данными / структурой, соответствующими вашему реальному проекту, и сгенерировать StackBlitz, если он все еще не работает.

Надеюсь, это поможет!

...