【问题标题】:Having Trouble Loading Earlier Messages in React-native GiftedChat Chat App with Firebase在使用 Firebase 的 React-native GiftedChat 聊天应用程序中加载早期消息时遇到问题
【发布时间】:2019-05-25 21:45:55
【问题描述】:

我一直在使用 Gifted-Chat 和 Firebase RealTime 数据库开发一个聊天应用程序(并使用 Expo 运行它)。此时,基本消息传递工作,但我试图让应用程序在用户向上滚动并点击出现的按钮时加载早期消息(我知道 GiftedChat 道具)。不幸的是,我在做这件事时遇到了麻烦,有点难过。

我知道有两个不同的问题我一直在遇到。

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

下面是我的聊天屏幕代码的相关部分,以及我的 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;

【问题讨论】:

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


    【解决方案1】:

    对于您的第一个问题,您应该使用=&gt; 函数声明您的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,
                };
             });
          }); 
      }
      ...
    }
    

    【讨论】:

    • 谢谢,这一切都有效。我对 React-native(第一个项目)还是很陌生,所以想知道为什么我应该在构造函数中声明状态?
    • This 可能会帮助您了解如何定义和声明类成员。
    • 谢谢,我没有意识到javascript有多么复杂。不过,在浏览完该页面后,我仍然对为什么需要使用构造函数来声明状态感到困惑,因为代码在应用您的第一个修复程序而不添加构造函数后对我有效。
    • 对不起,没关系,我想我终于大致了解了整个绑定的东西。如果您有机会研究如何加载旧消息,我将不胜感激。
    【解决方案2】:

    为了从 firebase 加载最后的消息,我建议在您的参考中使用 limitToLast 函数。之后,您应该在天才聊天中调用 append 之前按日期排序结果。

    【讨论】:

    • 我遇到的麻烦是弄清楚如何避免重新下载我已经拥有的所有消息。有没有办法做到这一点?
    【解决方案3】:

    第二个问题应该和这个问题一样How Firebase on and once differ?

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

    【讨论】:

      猜你喜欢
      • 2021-02-17
      • 2019-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多