React:使用setState竞争条件从firebase和store获取数据

时间:2018-06-08 20:36:27

标签: reactjs firebase setstate

从Firebase读取数据时,似乎我遇到setState的某种竞争条件。加载组件后,将调用侦听器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 :(得分:0)

不应该出现任何竞争条件,因为setState()每次调用时都会更改一次,在这种情况下,每个client快照都会由{{1}生成}事件包括已添加的现有child_added和新client

问题实际上可能与client的语法有关,每次都可能会突变/恢复setState()。相反,请尝试使用this.state.clients spread syntax...个对象追加到client并以不可变的方式更新/合并this.state.clients

this.state

使用个人Firebase项目,我能够将每个项目都等同于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] }); }); } } ,并在this.state.clientscomponentDidMount中相应地显示这些项目。如果您愿意,可以创建一个虚拟Firebase项目,其模拟数据/结构与您的实际项目相匹配,如果它仍然不起作用,则生成StackBlitz。

希望这有帮助!

答案 1 :(得分:0)

问题是您需要清除对Firebase的引用,否则将导致内存泄漏。在React中,通常是在 componentWillUnmount 中完成的。

使用您的示例,您需要添加以下内容:

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

您还需要在 componentDidMount 中修改代码,以便使用 this.clientsRef 使用局部变量的说明。

您可以在Firebase Blog上了解有关此内容的更多信息。