【问题标题】:React: Get data from firebase and store using setState race conditionReact:使用 setState 竞争条件从 firebase 获取数据并存储
【发布时间】:2018-06-08 20:36:26
【问题描述】:

从 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) })
      })
  }
}

【问题讨论】:

    标签: reactjs firebase setstate


    【解决方案1】:

    不应该有任何竞争条件,因为 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 的等效项,并在 componentDidMountcomponentWillMount 中相应地显示这些项目。如果您愿意,您可以创建一个虚拟 Firebase 项目,其模拟数据/结构与您的实际项目相匹配,如果仍然无法正常工作,则生成一个 StackBlitz。

    希望对您有所帮助!

    【讨论】:

    • 感谢您的帮助!这很好,但它并没有解决我的问题。当我从 DOM 中删除元素然后将其添加回来时,我的问题发生了。我通过隐藏元素而不是稍后删除并添加它们来解决问题。不知道为什么,但问题仅在删除元素然后将元素添加回 DOM 后才会发生。在启动时第一次将元素添加到哑元时,并没有发生此问题。为什么?
    • 我想我知道可能会发生什么,但需要在本地项目中尝试,除非您可以创建 StackBlitz 来演示模拟 Firebase 项目的问题。只是为了完全理解这个问题,几个问题。您是否表示在添加/删除的单个视图上有多个组件 ClientsTable 实例?如果是这样,它们是否全部执行与您在问题中所遇到的完全相同的 Firebase 查询,还是使用 Firebase 的 orderByChild()equalTo() 之类的东西有所不同?
    • 或者当您说“隐藏元素”时,您是指从 Firebase 列表查询返回的单个列表项吗? ClientsTable 是否在您的问题中对从 componentWillMount() 中的查询返回的项目执行 Firebase 操作,例如 push()set()remove()?您可能需要使用ClientsTable 功能的其他信息来更新您的问题。
    【解决方案2】:

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

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

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

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

    您可以在Firebase Blog 上阅读更多相关信息。

    【讨论】:

      猜你喜欢
      • 2016-10-30
      • 2015-08-01
      • 1970-01-01
      • 2019-11-20
      • 2014-05-08
      • 1970-01-01
      • 2016-10-10
      • 1970-01-01
      • 2012-04-08
      相关资源
      最近更新 更多