2017-10-07 45 views
1

下面是一个从firebase数据库获取消息的函数,但它只有setState只有一个消息。关于反应中的setState

但是,console.log可以记录对象中的多个消息。 我的功能有什么问题吗?

getMessages(){ 
var messages = []; 
firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => { 
    //alert(JSON.stringify(dataSnapshot.val())); 
    dataSnapshot.forEach((child) => { 
    firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{ 
     //alert(JSON.stringify(messages)); 
     messages.push({ 
     _id: Math.round(Math.random() * 1000000), 
     text: message.val().text, 
     createdAt: new Date(message.val().timestamp), 
     user: { 
      _id: 1, 
      name: 'Developer', 
     }, 
     }); 
     this.setState({ 
     messages: messages 
     }); 
     console.log('woooo'+JSON.stringify(messages)); 
    }); 
    }); 
}); 
} 

回答

1

您设置forEach块内的状态。尝试在迭代块外移动它

正如JanneKlouman所说的,当您在进行异步调用时,将它从iterration块中移除并不够好。 您可以创建一个新的数组,并将其设置在每个迭代状态,反应器会批量的设置状态的呼叫:

function getMessages() { 
    var messages = []; 
    firebaseApp.database().ref('users/' + firebase.auth().currentUser.uid + '/userChat/' + firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => { 
    //alert(JSON.stringify(dataSnapshot.val())); 
    dataSnapshot.forEach((child) => { 
     firebaseApp.database().ref('messages').child(child.key).once("value", (message) => { 
     const newMessage = { 
      _id: Math.round(Math.random() * 1000000), 
      text: message.val().text, 
      createdAt: new Date(message.val().timestamp), 
      user: { 
      _id: 1, 
      name: 'Developer', 
      }, 
     } 
     const nextState = this.state.messages.map(message => { 
      return { 
      ...message, 
      user: {...meesage.user} // i think we must do this in order to break out of the reference as spreading will only work on a shallow level 
      } 
     }); 
     this.setState({ 
      messages: [...nextState, newMessage] 
     }); 
     }); 
    }); 
    }); 
} 
+0

这是不是等同于'this.setState({messages:[]})',因为它在消息firebase回调被触发之前运行? –

+0

@JanneKlouman看起来像是对的,超出了第二个'ref'范围。 –

+0

有没有办法将所有的消息保存在变量中,然后setState只保存一次? – wo99999

0

尝试设置状态之前克隆数组:

getMessages(){ 
    let messages = []; 
    firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => { 
    dataSnapshot.forEach((child) => { 
     firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{ 
     const message = { 
      _id: Math.round(Math.random() * 1000000), 
      text: message.val().text, 
      createdAt: new Date(message.val().timestamp), 
      user: { 
      _id: 1, 
      name: 'Developer', 
      }, 
     }; 

     // Clone messages 
     messages = [...messages, message]; 

     this.setState({ messages }); 
     }); 
    }); 
    }); 
} 
+0

'spread'运算符只能在一个层次上工作,这意味着'meesage.user'将保持对该状态中对象的引用。 –