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 :
- When I navigate from one chat channel to another the total messages cummulate.
- When I come back to an earlier channel, the messages for the same chat channel repeat more than once.
- 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 = () => {
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);