Javascript 在React Native上获取异步Firebase数据

Javascript 在React Native上获取异步Firebase数据,javascript,firebase,react-native,async-await,Javascript,Firebase,React Native,Async Await,我正在使用Firebase构建React本机应用程序。我在我的一个组件中使用以下方法(以及其他方法)从Firebase获取数据: loadMessagesFromFirebase(chatId){ let messageList = []; let data = {}; let message = {}; const dataRef = firebase.database().ref('chats').child(chatId); dataRef.on('

我正在使用Firebase构建React本机应用程序。我在我的一个组件中使用以下方法(以及其他方法)从Firebase获取数据:

loadMessagesFromFirebase(chatId){
    let messageList = [];
    let data = {};
    let message = {};
    const dataRef = firebase.database().ref('chats').child(chatId);
    dataRef.on('value', datasnap=>{
        data = datasnap.val()
    })
    for (var sayer in data){
        for (var m in data[sayer]){
            message = {sayer: sayer, text: m.text, time: new Date(m.created)};
            messageList.push(message);
        }
    }
    messageList.sort((a,b) => (a.time > b.time) ? 1: -1);
    this.setState({messageList: messageList});
  }
问题是,有时数据将作为空字典(对象{})加载,因此消息列表将为空。我想这是因为我没有给Firebase足够的时间来加载。如何使此函数异步,以便可以向组件添加“加载”状态,并且在完成加载之前不显示消息信息

async componentDidMount(){
    firebase.initializeApp(FirebaseConfig);
    this.loadMessagesFromFirebase(this.state.chatId);
    //once the messages are done loading
    this.setState({{loading: false}})
}

此外,有没有办法确保,如果数据以空字典的形式返回,那是因为Firebase已完成加载,而不是因为没有此聊天id的数据?

多亏了vvs的评论,才明白了这一点。所有必须异步完成的操作都必须进入dataref.on()函数

loadMessagesFromFirebase(chatId){
    let messageList = [];
    let data = {};
    let message = {};
    const dataRef = firebase.database().ref('chats').child(chatId);
    dataRef.on('value', datasnap=>{
        data = datasnap.val()
        for (var sayer in data){
            for (var m in data[sayer]){
                message = {sayer: sayer, text: m.text, time: new Date(m.created)};
                messageList.push(message);
            }
        }
        messageList.sort((a,b) => (a.time > b.time) ? 1: -1);
        this.setState({messageList: messageList});
        this.setState({{loading: false}})
    })
  }
这就是函数的调用方式:

componentDidMount(){
    this.loadMessagesFromFirebase(this.state.chatId);
}

(将firebase.initializeapp(FirebaseConfig)放在其中实际上会导致问题-它必须运行一次,并且必须更早,例如在设置应用程序时)

回答这个问题,尽管OP似乎已经找到了答案,因为他没有解释基本概念

Firebase sdk使用异步编程和观察者模式提供实时更新

在React Native world上获取异步Firebase数据的正确方法如下所示

  • 在应用程序启动期间仅初始化firebase sdk一次。就React而言,这可以在顶级应用程序组件的构造函数中完成。 有关步骤,请参阅firebase文档

  • 在component构造函数或componentDidMount内部,设置对firebase函数的调用以加载数据
    componentDidMount(){this.loadMessagesFromFirebase(this.state.chatId);}

  • 在加载消息函数中,向上异步调用firebase realtor数据库。更多阅读

  • 这里要记住的主要一点是,在数据可用后必须运行的所有代码都必须在写入异步回调时触发。修改问题中的示例代码

    loadMessagesFromFirebase(chatId){
        let data = {};
        let output = {};
        const dataRef = firebase.database().ref('chats').child(chatId);
        dataRef.once('value', datasnap=>{
            data = datasnap.val();
    
            // Do something really smart with the data and assign it to output
            ...... 
            output = data;
            // set updates to the state
            this.setState({output: output});
        })
      }
    
    注意使用
    一次
    而不是
    开启
    功能。 这是因为订阅上的观察者
    可能导致每次数据发生更改时都会触发回调。如果组件被设计为只获取一次数据,这可能会导致不良后果

    进一步阅读

    如果希望在每次数据更改时更新组件,则使用
    on
    功能设置对该数据的订阅。但是在这种情况下,取消
    组件willunmount

    这可以概括如下

    `
    // inside componentDidMount 
    this.onValueChange = ref.on('value', function(dataSnapshot) { ... });
    
    
    // Sometime later.... Inside componentWillUnmount
    ref.off('value', this.onValueChange);`