在多频道聊天应用程序中,如何显示仅属于特定聊天频道的消息?
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。
实际结果:
- 当我从一个聊天频道导航到另一个聊天频道时,消息总数会累积。
- 当我回到较早的频道时,同一聊天频道的消息会重复多次。
- 警告:遇到两个 children 使用相同的密钥
%s
。密钥应该是唯一的,以便组件在更新期间保持其身份。 Non-unique 键可能会导致 children 被重复 and/or 省略 — 该行为不受支持,可能会在未来的版本中更改。%s
到目前为止我尝试了什么?
1. 每次用户使用 componentDidUpdate 从一个频道导航到另一个频道时,重新启动对新聊天频道的订阅。
2. 每次用户更改聊天频道时,将消息数组的状态设置为空数组。
3、在Firebase中取消订阅之前的节点,在componentDidUpdate中订阅一个新的节点。这里的节点表示在 Firebase 中由 ID 标识的聊天频道。每个节点包含 children,即与该特定聊天频道相关的所有消息。
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);
根据 Brett Gregson 的建议和 Mike Kamerman 的回答,我实施了以下解决方案。
- 当用户从一个频道导航到另一个频道时,我会触发一组功能。
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();
}
};
- 我将消息状态(消息数组)设置为空数组以及 async/await 机制。 getMessages 函数获取新频道的消息。这样属于前一组的消息被清除,UI中没有消息的堆积。
switchSession = async () => {
await this.setState({ messages: [] });
await this.getMessages();
}
环境: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。
实际结果:
- 当我从一个聊天频道导航到另一个聊天频道时,消息总数会累积。
- 当我回到较早的频道时,同一聊天频道的消息会重复多次。
- 警告:遇到两个 children 使用相同的密钥
%s
。密钥应该是唯一的,以便组件在更新期间保持其身份。 Non-unique 键可能会导致 children 被重复 and/or 省略 — 该行为不受支持,可能会在未来的版本中更改。%s
到目前为止我尝试了什么? 1. 每次用户使用 componentDidUpdate 从一个频道导航到另一个频道时,重新启动对新聊天频道的订阅。 2. 每次用户更改聊天频道时,将消息数组的状态设置为空数组。 3、在Firebase中取消订阅之前的节点,在componentDidUpdate中订阅一个新的节点。这里的节点表示在 Firebase 中由 ID 标识的聊天频道。每个节点包含 children,即与该特定聊天频道相关的所有消息。
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);
根据 Brett Gregson 的建议和 Mike Kamerman 的回答,我实施了以下解决方案。
- 当用户从一个频道导航到另一个频道时,我会触发一组功能。 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();
}
};
- 我将消息状态(消息数组)设置为空数组以及 async/await 机制。 getMessages 函数获取新频道的消息。这样属于前一组的消息被清除,UI中没有消息的堆积。
switchSession = async () => {
await this.setState({ messages: [] });
await this.getMessages();
}