每当添加新数据时,FlatList会多次从Firebase重新呈现数据

时间:2018-05-21 19:07:48

标签: javascript react-native firebase-realtime-database expo react-native-flatlist

我正在尝试使用react native和firebase构建聊天应用程序界面,并且在更新从我的数据库中提取的数据时遇到问题。我可以将现有数据加载到我正在使用的Flatlist中:

const firebaseApp = firebase.initializeApp(firebaseConfig);
let db = firebaseApp.database();
let ref = db.ref("/room");

 componentDidMount() {
      ref.on('value', function(snapshot) {
        snapshot.forEach(function (childSnapshot){
          childData.push(childSnapshot.val());
        });
        this.setState({
          messages: childData
        });
       messageCount = snapshot.numChildren();
     }.bind(this));
 }

Flatlist Code:

<KeyboardAvoidingView style={styles.inputContainer}>
      <FlatList
          data={this.state.messages}
          // renderItem={({item}) =><Text>{item.contents}</Text>}
          keyExtractor = {item => item.timestamp}
          renderItem={({item}) => <Bubble style={{margin: 10}} 
          color="#FFC800" arrowPosition='right'>{item.contents}</Bubble>}
            />}
        />
        <Button onPress={()=>{this.onPressButton()}} title="Send">Click me</Button>      
      </KeyboardAvoidingView>

这是我在文本输入中添加文本的地方

function addMessage(messageText) {
  messageCount++;
  firebase.database().ref('room/'+messageCount).set({
      contents: messageText,
      timestamp: firebase.database.ServerValue.TIMESTAMP
  });
}

该代码给了我以下结果,这就是我想要的(忽略可怕的样式): enter image description here

但每当我尝试发送消息时,它都会正确地添加到数据库中,但平面列表会更新以显示:

enter image description here

前一条消息和新消息多次呈现的位置。将新项目从数据库呈现到平面列表的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

查看您的代码,我无法找到您初始化childData的位置。

假设您的数据库是正确的,那么在将您的数据库分配到您的州之前,您似乎没有清除childData

this.setState({
  messages: childData
});

因此,当您的代码运行此推送childData.push(childSnapshot.val());时,它会向您的数组添加所有新内容并保留旧内容。

示例:

第一个州:

// snapshot.val() contains ['Hello']
childData = ['Hello']

提交文字:World!

更新状态:

// snapshot.val() contains ['Hello', 'World']
childData = ['Hello', 'Hello', 'World!']

要解决此问题的建议是仅使用新值分配数组,因此您可以执行类似push

的操作,而不是使用childData = snapshot.val()

我还建议您使用console.log调试代码,以便了解snapshot.val()childDatathis.state.messages

正在重新审核的内容

希望有所帮助

编辑: 再次阅读,可能的问题也可能是因为JS是同步的,所以在setState完成之前调用forEach。解决方案可能是使用async/await https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

这样的事情:

ref.on('value', async (snapshot) => {
  const childData = await snapshot.map((childSnapshot) => {
   childSnapshot.val();
  });
  this.setState({
    messages: childData
  });
 (...)

仅考虑以上代码作为示例

希望有所帮助