如何在多通道聊天应用中只显示与特定聊天通道相关的消息?

huangapple go评论72阅读模式
英文:

In a multichannel chat application how can I display messages pertaining only to a specific chat channel?

问题

环境: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上应仅显示与给定频道相关的消息。

实际结果:

  1. 当我从一个聊天频道导航到另一个时,总消息会累积。
  2. 当我回到早期的频道时,相同聊天频道的消息会重复多次。
  3. 警告:遇到两个具有相同键的子元素,%s。键应该是唯一的,以便组件在更新时保持其标识。非唯一的键可能导致子元素重复或被省略 - 此行为不受支持,可能会在将来的版本中更改。%s

我迄今为止尝试了什么?

  1. 每当用户从一个频道导航到另一个频道时,使用componentDidUpdate重新启动对新聊天频道的订阅。
  2. 每当用户更改聊天频道时,将消息数组的状态设置为空数组。
  3. componentDidUpdate中取消订阅以前的Firebase节点,并订阅新节点。在这里,节点表示Firebase中由ID标识的聊天频道。每个节点包含所有与该特定聊天频道相关的消息的子元素。
async componentDidMount() {
  await this.getSessionInfo();
  await this.getCurrentProfile();
  await this.getMessages();
};

async componentDidUpdate(prevProps) {
  /* sessionID代表一个聊天频道和Firebase中对应的节点 */
  /* 如果用户从一个频道导航到另一个频道,我们将建立与新节点的连接,并获取相应的消息 */
  if (this.props.navigation.state.params.sessionID !== prevProps.navigation.state.params.sessionID) {
    await this.getSessionInfo();
    await this.getCurrentProfile();
    /* 订阅新聊天频道 */
    await this.ref();
    await this.getMessages();
  }
};

async componentWillUnmount() {
  /* 取消数据库订阅 */
  await this.off();
}

/* 在组件挂载在屏幕上后获取要显示的消息 */
getMessages = () => {
  this.connect(message => {
    this.setState(previousState => ({
      messages: GiftedChat.append(previousState.messages, message),
    }))
  });
}

/* 每个sessionID对应一个聊天频道和Firebase中的节点 */
ref = () => {
  return database.ref(`/sessions/${this.state.sessionID}`);
}

/* 获取与给定聊天频道相关的最后20条消息并监听解析新的传入消息 */
connect = (callback) => {
  this.ref()
    .limitToLast(20)
    .on('child_added', snapshot => callback(this.parse(snapshot)));
}

/* 在GiftedChat格式中解析新创建的消息对象 */
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;
};

/* 接受消息数组的函数,然后循环遍历消息 */
send = (messages) => {
  for (let i = 0; i < messages.length; i++) {
    const { text, user } = messages[i];
    const message = {
      text,
      user
    };
    this.append(message);
  }
};

/* append函数将保存带有唯一ID的消息对象 */
append = message => this.ref().push(message);

希望这有助于解决你的问题。如果你需要进一步的帮助,请随时提问。

英文:

Environment : expo 36.0.0 / React Native 0.61 / react-native-gifted-chat 0.13.0 / firebase 7.6.0

My goal: Render only messages specific to a specific chat channel on the Gifted Chat UI.

Expected results: Only messages pertaining to a given channel should be displayed on the Gifted Chat UI.

Actual results :

  1. When I navigate from one chat channel to another the total messages cummulate.
  2. When I come back to an earlier channel, the messages for the same chat channel repeat more than once.
  3. Warning: Encountered two children with the same key, %s. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.%s

What have I tried so far?

  1. Relaunch subscription to new chat channel every time the user navigates from one channel to another using componentDidUpdate.
  2. Set State of messages array to an empty array every time user changes chat channel.
  3. Unsubscribe from the previous node in Firebase and subscribe to a new node in componentDidUpdate. Here node represents the chat channel identified by an ID in Firebase. Each node contains children that are all the messages pertaining to that specific chat channel.
  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 = () =&gt; {
this.connect(message =&gt; {
this.setState(previousState =&gt; ({
messages: GiftedChat.append(previousState.messages, message),
}))
});
}
/* Each sessionID corresponds to a chat channel and node in Firebase  */
ref = () =&gt; {
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) =&gt; {
this.ref()
.limitToLast(20)
.on(&#39;child_added&#39;, snapshot =&gt; callback(this.parse(snapshot)));
}
/* newly created message object in GiftedChat format */
parse = snapshot =&gt; {
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) =&gt; {
for (let i = 0; i &lt; 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 =&gt; this.ref().push(message);

答案1

得分: 3

  1. 当用户从一个频道导航到另一个频道时,我触发一系列函数。
    this.ref() 函数订阅新的频道(Firebase 中的节点)。
  async componentDidUpdate(prevProps) {
    if (this.props.navigation.state.params.sessionID !== prevProps.navigation.state.params.sessionID) {
      await this.getSessionInfo();
      await this.ref();
      await this.switchSession();
    }
  };
  1. 我设置了消息状态,它是一个消息数组,初始为空数组,并使用了异步/等待机制。getMessages 函数获取新频道的消息。这样,前一组消息将被清除,UI 中不会积累消息。
  switchSession = async () => {
    await this.setState({ messages: [] });
    await this.getMessages();
  }
英文:

Following Brett Gregson's advice and Mike Kamerman's answer, I implemented the following solution.

  1. When the user navigates from one channel to another, I trigger a set of functions.
    this.ref() function subscribes to new channel (node in Firebase).
  async componentDidUpdate(prevProps) {
if (this.props.navigation.state.params.sessionID !== prevProps.navigation.state.params.sessionID) {
await this.getSessionInfo();
await this.ref();
await this.switchSession();
}
};
  1. I set the messages state which is an array of messages to en empty array along with async/await mechanism. The getMessages function fetches the messages of new channel. This way messages belonging to preceding group are cleared and there is no accumulation of messages in the UI.
  switchSession = async () =&gt; {
await this.setState({ messages: [] });
await this.getMessages();
}

huangapple
  • 本文由 发表于 2020年1月3日 18:47:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/59577188.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定