Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/458.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在多频道聊天应用程序中,如何仅显示与特定聊天频道相关的消息?_Javascript_React Native_Firebase Realtime Database_React Native Firebase_React Native Gifted Chat - Fatal编程技术网

Javascript 在多频道聊天应用程序中,如何仅显示与特定聊天频道相关的消息?

Javascript 在多频道聊天应用程序中,如何仅显示与特定聊天频道相关的消息?,javascript,react-native,firebase-realtime-database,react-native-firebase,react-native-gifted-chat,Javascript,React Native,Firebase Realtime Database,React Native Firebase,React Native Gifted Chat,环境:expo 36.0.0/React Native 0.61/React Native gifted chat 0.13.0/firebase 7.6.0 我的目标:仅在Gifted chat UI上呈现特定于特定聊天频道的消息 预期结果:只有与给定频道相关的消息才会显示在Gifted Chat UI上 实际结果: 当我从一个聊天频道导航到另一个聊天频道时,总的消息会累积起来 当我回到以前的频道时,同一聊天频道的消息会重复多次 警告:遇到两个具有相同密钥的子项,%s。键应该是唯一的,以便组件

环境:expo 36.0.0/React Native 0.61/React Native gifted chat 0.13.0/firebase 7.6.0

我的目标:仅在Gifted chat UI上呈现特定于特定聊天频道的消息

预期结果:只有与给定频道相关的消息才会显示在Gifted Chat UI上

实际结果:

  • 当我从一个聊天频道导航到另一个聊天频道时,总的消息会累积起来
  • 当我回到以前的频道时,同一聊天频道的消息会重复多次
  • 警告:遇到两个具有相同密钥的子项,
    %s
    。键应该是唯一的,以便组件在更新期间保持其标识。非唯一键可能会导致复制和/或忽略子项-不支持该行为,并且可能在将来的版本中更改。%s
  • 到目前为止我试过什么? 1.每当用户使用componentDidUpdate从一个频道导航到另一个频道时,重新启动对新聊天频道的订阅。 2.每次用户更改聊天频道时,将messages数组的状态设置为空数组。 3.取消订阅Firebase中的上一个节点,并订阅componentDidUpdate中的新节点。此处节点表示由Firebase中的ID标识的聊天频道。每个节点都包含与特定聊天频道相关的所有消息的子节点

      async componentDidMount() {
        await this.getSessionInfo();
        await this.getCurrentProfile();
        await this.getMessages();
      };
    
      async componentDidUpdate(prevProps) {
        /* sessionID represent a chat channel and corresponding node in Firebase */
        /* If user navigates from one channel to another we establish a connection with new node and get the 
        corresponding messages */
        if (this.props.navigation.state.params.sessionID !== prevProps.navigation.state.params.sessionID) {
          await this.getSessionInfo();
          await this.getCurrentProfile();
          /* Subscribe to new chat channel */
          await this.ref();
          await this.getMessages();
        }
      };
    
      async componentWillUnmount() {
        /* Unsubscribe from database */
        await this.off();
      }
    
      /* Get messages to display after component is mounted on screen */
      getMessages = () => {
        this.connect(message => {
          this.setState(previousState => ({
            messages: GiftedChat.append(previousState.messages, message),
          }))
        });
      }
    
      /* Each sessionID corresponds to a chat channel and node in Firebase  */
      ref = () => {
        return database.ref(`/sessions/${this.state.sessionID}`);
      }
    
      /* Fetch last 20 messages pertaining to given chat channel and lister to parse new incoming message */
      connect = (callback) => {
        this.ref()
          .limitToLast(20)
          .on('child_added', snapshot => callback(this.parse(snapshot)));
      }
    
        /* newly created message object in GiftedChat format */
        parse = snapshot => {
        const { timestamp: numberStamp, text, user } = snapshot.val();
        const { key: _id } = snapshot;
        const timestamp = new Date(numberStamp);
    
        const message = {
          _id,
          timestamp,
          text,
          user,
        };
        return message;
      };
    
      /* function that accepts an array of messages then loop through messages */
      send = (messages) => {
        for (let i = 0; i < messages.length; i++) {
          const { text, user } = messages[i];
          const message = {
            text,
            user
          };
          this.append(message);
        }
      };
    
      /* append function will save the message object with a unique ID */
      append = message => this.ref().push(message);
    
    
    异步组件didmount(){ 等待此消息。getSessionInfo(); 等待此消息。getCurrentProfile(); 等待此消息。getMessages(); }; 异步组件更新(prevProps){ /*sessionID表示Firebase中的聊天频道和相应节点*/ /*如果用户从一个通道导航到另一个通道,我们将与新节点建立连接并获取 相应的消息*/ if(this.props.navigation.state.params.sessionID!==prevProps.navigation.state.params.sessionID){ 等待此消息。getSessionInfo(); 等待此消息。getCurrentProfile(); /*订阅新的聊天频道*/ 等待这个; 等待此消息。getMessages(); } }; 异步组件willunmount(){ /*取消订阅数据库*/ 等待这个。关(); } /*在屏幕上安装组件后获取要显示的消息*/ getMessages=()=>{ 此.connect(消息=>{ this.setState(previousState=>({ 消息:giftechat.append(previousState.messages,message), })) }); } /*每个sessionID对应于Firebase中的聊天频道和节点*/ ref=()=>{ 返回database.ref(`/sessions/${this.state.sessionID}`); } /*获取与给定聊天频道和列表器相关的最后20条消息,以解析新的传入消息*/ 连接=(回调)=>{ this.ref() .limitToLast(20) .on('child_added',snapshot=>callback(this.parse(snapshot)); } /*新创建的GifteChat格式的消息对象*/ 解析=快照=>{ const{timestamp:numberStamp,text,user}=snapshot.val(); const{key:_id}=快照; const timestamp=新日期(numberStamp); 常量消息={ _身份证, 时间戳, 文本, 用户, }; 返回消息; }; /*函数,该函数接受消息数组,然后在消息中循环*/ 发送=(消息)=>{ for(设i=0;ithis.ref().push(消息);
    根据Brett Gregson的建议和Mike Kamerman的回答,我实现了以下解决方案

  • 当用户从一个频道导航到另一个频道时,我触发一组函数。 此.ref()函数订阅新通道(Firebase中的节点)
  • 我使用异步/等待机制将消息数组中的消息状态设置为空数组。getMessages函数获取新通道的消息。这样,属于前一组的消息将被清除,并且UI中不会累积消息
    尝试使用类似于Mike Kamermans在此处的回答的链接将状态设置为emtpy数组非常感谢Brett花时间回答我的问题,以及Ivan和Frank编辑我的问题并使其更易于理解。Mike Kamerman答案中的概念解释帮助我实现了选项1的一个版本,该版本在他的答案中有所体现。很高兴你找到了答案
      async componentDidUpdate(prevProps) {
        if (this.props.navigation.state.params.sessionID !== prevProps.navigation.state.params.sessionID) {
          await this.getSessionInfo();
          await this.ref();
          await this.switchSession();
        }
      };
    
      switchSession = async () => {
        await this.setState({ messages: [] });
        await this.getMessages();
      }