使用Firebase在本机的GiftedChat聊天应用程序中加载较早的消息时遇到问题

时间:2018-12-28 00:06:20

标签: javascript firebase react-native firebase-realtime-database react-native-gifted-chat

我一直在使用Gifted-Chat和Firebase RealTime数据库(并在Expo上运行它)开发一个聊天应用程序。在这一点上,基本的消息传递有效,但是当用户向上滚动并单击出现的按钮时,我试图启用应用程序以加载较早的消息(我知道为此提供了GiftedChat道具)。不幸的是,我在执行此操作时遇到了麻烦,感到有些困惑。

我已经意识到有两个独立的问题。

  1. 单击loadEarlier按钮会给我一个undefined is not a function (near '...this.setState...'运行时错误(很明显,我放置在此处的骨架函数有问题)。
  2. 更大的问题是,我仍然不清楚如何在当前加载的最早邮件之前下载 n 条邮件。我已经向the GiftedChat examplethis post寻求帮助,但必须承认我仍然迷路(我能想到的最好的办法是,我需要对消息进行排序(可能按时间戳排序),以某种方式获得正确的范围,然后解析它们并将它们放在状态中的message数组前面,但我不知道如何做到这一点,尤其是后面的部分。

下面是我的聊天屏幕的代码相关部分,以及我的firebase数据库结构的屏幕截图。对于这两个问题,我将不胜感激。

// Your run of the mill React-Native imports.
import React, { Component } from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import * as firebase from 'firebase';
// Our custom components.
import { Input } from '../components/Input';
import { Button } from '../components/Button';
import { BotButton } from '../components/BotButton';
// Array of potential bot responses. Might be a fancy schmancy Markov
// chain like thing in the future.
import {botResponses} from '../Constants.js';
// Gifted-chat import. The library takes care of fun stuff like
// rendering message bubbles and having a message composer.
import { GiftedChat } from 'react-native-gifted-chat';
// To keep keyboard from covering up text input.
import { KeyboardAvoidingView } from 'react-native';
// Because keyboard avoiding behavior is platform specific.
import {Platform} from 'react-native';

console.disableYellowBox = true;

class Chat extends Component {
    state = {
        messages: [],
        isLoadingEarlier: false,
    };

    // Reference to where in Firebase DB messages will be stored.
    get ref() {
        return firebase.database().ref('messages');
    }

    onLoadEarlier() {
        this.setState((previousState) => {
          return {
            isLoadingEarlier: true,
          };
        });
        console.log(this.state.isLoadingEarlier)
        this.setState((previousState) => {
            return {
                isLoadingEarlier: false,
            };
        });
    }

    // Get last 20 messages, any incoming messages, and send them to parse.
    on = callback =>
        this.ref
          .limitToLast(20)
          .on('child_added', snapshot => callback(this.parse(snapshot)));
    parse = snapshot => {
        // Return whatever is associated with snapshot.
        const { timestamp: numberStamp, text, user } = snapshot.val();
        const { key: _id } = snapshot;
        // Convert timestamp to JS date object.
        const timestamp = new Date(numberStamp);
        // Create object for Gifted Chat. id is unique.
        const message = {
            _id,
            timestamp,
            text,
            user,
        };
        return message;
    };
    // To unsubscribe from database
    off() {
        this.ref.off();
    }

    // Helper function to get user UID.
    get uid() {
        return (firebase.auth().currentUser || {}).uid;
    }
    // Get timestamp for saving messages.
    get timestamp() {
        return firebase.database.ServerValue.TIMESTAMP;
    }

    // Helper function that takes array of messages and prepares all of
    // them to be sent.
    send = messages => {
        for (let i = 0; i < messages.length; i++) {
            const { text, user } = messages[i];
            const message = {
                text,
                user,
                timestamp: this.timestamp,
            };
            this.append(message);
        }
    };

    // Save message objects. Actually sends them to server.
    append = message => this.ref.push(message);

    // When we open the chat, start looking for messages.
    componentDidMount() {
        this.on(message =>
          this.setState(previousState => ({
              messages: GiftedChat.append(previousState.messages, message),
          }))
        );
    }
    get user() {
        // Return name and UID for GiftedChat to parse
        return {
            name: this.props.navigation.state.params.name,
            _id: this.uid,
        };
    }
    // Unsubscribe when we close the chat screen.
    componentWillUnmount() {
        this.off();
    }

    render() {
        return (
        <View>
            <GiftedChat
                loadEarlier={true}
                onLoadEarlier={this.onLoadEarlier}
                isLoadingEarlier={this.state.isLoadingEarlier}
                messages={this.state.messages}
                onSend={this.send}
                user={this.user}
            />
         </View>
        );
    }

}
export default Chat;

Screenshot of DB

3 个答案:

答案 0 :(得分:1)

对于第一个问题,应使用onLoadEarlier函数声明=>,以获取当前实例this,即您的代码应如下所示:

onLoadEarlier = () => {
    this.setState((previousState) => {
      return {
        isLoadingEarlier: true,
      };
    }, () => {
       console.log(this.state.isLoadingEarlier)
       this.setState((previousState) => {
          return {
             isLoadingEarlier: false,
          };
       });
    }); 
}

此外,setState本质上是异步的,因此您应该依赖于setState的第二个参数,即回调,以确保下一行代码同步执行。

最后,如果您使用class语法,则应在constructor中声明状态,如下所示:

class Chat extends Component {
   constructor (props) {
      super (props);
      state = {
         messages: [],
         isLoadingEarlier: false,
      };
   }
  ......

    onLoadEarlier = () => {
      this.setState((previousState) => {
        return {
          isLoadingEarlier: true,
        };
      }, () => {
         console.log(this.state.isLoadingEarlier)
         this.setState((previousState) => {
            return {
               isLoadingEarlier: false,
            };
         });
      }); 
  }
  ...
}

对于第二个答案,我会在某个时候更新答案以帮助您解决。

希望这会有所帮助。快乐编码:)

答案 1 :(得分:0)

要从firebase加载最后一条消息,建议您在参考上使用limitToLast函数。之后,您应按日期顺序对结果进行排序,然后在有才华的聊天中调用追加。

答案 2 :(得分:0)

对于第二个问题,该问题应与How Firebase on and once differ?相同

您可以在Firebase中使用过滤器功能,例如,使用createdAt字段与上次加载的邮件进行比较以加载更多邮件。