Updating messages attributes will not trigger message bubble re-render. To be more precise, updating a seen (boolean) property (similar to seen or received), will not trigger the message to be re-rendered. Messages are re-rendered only when a new message is added to the messages array, not when one particular message is updated.
// https://github.com/FaridSafi/react-native-gifted-chat/blob/master/src/MessageContainer.js#L67
componentWillReceiveProps(nextProps) {
if (this.props.messages === nextProps.messages) {
return;
}
const messagesData = this.prepareMessages(nextProps.messages);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(messagesData.blob, messagesData.keys)
});
}
Messages, or single message, should be updated and re-rendered whenever any of its properties are updated.
Removing the empty return within componentWillReceiveProps of MessageContainer.js, which fails to properly compare if messages are truly the same or not.
// https://github.com/FaridSafi/react-native-gifted-chat/blob/master/src/MessageContainer.js#L67
componentWillReceiveProps(nextProps) {
//if (this.props.messages === nextProps.messages) {
//return;
//}
const messagesData = this.prepareMessages(nextProps.messages);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(messagesData.blob, messagesData.keys)
});
}
Please, paste you GitedChat component :)
<GiftedChat
ref={giftedChat => {
this.giftedChat = giftedChat;
}}
messages={
this.state.toggleOffers
? this.props.messages.filter(message => message.messageType === 'offer')
: this.props.messages
}
onSend={this.onSend.bind(this)}
user={{
_id: this.props.myself.id,
match: this.props.match
}}
renderMessage={this.renderMessage.bind(this)}
renderMessageImage={this.renderMessageImage.bind(this)}
renderFooter={this.renderFooter.bind(this)}
isAnimated
loadEarlier={!!this.props.paginationMeta.next}
onLoadEarlier={this.onLoadEarlier.bind(this)}
isLoadingEarlier={false}
bottomOffset={Platform.OS === 'ios' ? 49 : 0}
renderTime={() => {}}
placeholder={I18n.t('chat.typeAMessage')}
renderInputToolbar={
this.props.match && this.props.match.chat_user && this.props.match.chat_user.disabled
? this.disabledChatFooter.bind(this)
: null
}
placeholderTextColor={theme.colors.input.placeholder}
textInputStyle={{ color: theme.colors.input.text }}
textStyle={styles.sendButton}
onInputTextChanged={this.onTextChanged.bind(this)}
text={this.props.currentMessage}
label={I18n.t('chat.sendMessage')}
/>
That may cause performance issue.
Yes I know. However, with that piece of code in place, messages aren't re-rendered unless the entire component is re-rendered, and that's a nasty bug as well.
Maybe you can add it as an option... 馃
I was actually thinking about that after I replied but didn't know if that would be an acceptable solution :) Maybe I'll be able to do it before the winter holidays.
@cooperka @brunocascio any thoughts?
Mmmmm, I think you are using always props instead of state.
messages={
this.state.toggleOffers
? this.props.messages.filter(message => message.messageType === 'offer')
: this.props.messages
}
BTW, I have implemented that before in the same way (using state inside the component).
Performance issues could be resolved when we'll migrate to FlatList :D
@brunocascio messages are passed down to the MessageContainer.js component. It doesn't matter if where GC component is used the messages are stored in the _state_ or in _props_. Whenever they change, _componentWillReceiveProps_ is triggered and the return statement blocks the re-render.
But why not move the cdu to children? And add option to move optimisation from container to children.
On children you can fine tune the update requirement... one by one.
I mean keep the default behavior as is but add new option to move it to Message composent...
I see @brunocascio PR here https://github.com/FaridSafi/react-native-gifted-chat/pull/629 , which might fix the issue I think. Any idea on the progress on that one?
I prefer to release a new version removing a lot of "patches", supporting newest rn versions and changing the way to customize components (time, bubble, etc).
Nowadays, migrate to FlatList could be introduce breaking changes that are not retro-compatible with current or previous versions...
@cooperka @xcarpentier What do you think?
I can create a new branch starting the new UI/API.
I鈥檓 ok with creating a new branch and cleaning step by step to be able to migrate to FlatList.
But I prefer to wait having a good code coverage before, a tests harness.
I will add some initial tests tomorow...
Sounds good! I'll be watching it.
It's often easier to merge several smaller updates rather than creating a branch for a large set of changes. imo PRs should each be as minimal as possible to achieve a finite goal.
Maybe we can get it all on master and then publish one major version bump, but even if we release several smaller changesets it should be perfectly fine.
What if we use lodash.isequal to compare the messages, having
import isEqual from 'lodash.isequal';
if (isEqual(this.props.messages,nextProps.messages)) {
return;
}
instead of
if (this.props.messages === nextProps.messages) {
return;
}
Yes but there is a dependency of shallowequal.
I mean it鈥檚 ok but using shallowequal
We've managed to do it externally without causing performance issues. I guess the "bug" can be closed as it hard to reproduce for others and it won't happen on flatlist implementation.
@webraptor
Can you explain your solution? I have similar issue.
can there be an example for the feature like sent,pending so we will know how to update a bubble?
I couldnt find a good solution for updating rngc bubble.
I want to update my bubble message when I click on a button.
example:
when I send audio to someone and when the otherone plays my audio, that specific audio should be updated
I am also pretty stuck on this one here. Currently I can't update the "ticks" without doing some nasty .append() stuff before. It should be possible to re-render a single bubble.
I've been trying to implement message reactions similar to Facebook messenger, but on Android only the most recent message and the first message update properly when their props update. Like if I tap on a message to bring up the reaction bar, the reaction bar (which I implement as an absolute positioned view on top of my custom message bubble) will only render if its the top or most recent message.
Not sure if this is the "best" way to do it...but I was able to get the pending/sent to update properly by using the GiftedChat.append function. I store all of my messages in local state. I have it setup so that when the user presses the send button, it immediately appends the message to the state and it renders on the screen with pending true. Then, when I get a notification that the message was added to the server I find it in state and update the pending to false and set sent to true.
This is the code that works for me. I haven't ran any type of benchmarks to see if there's a performance hit, but it provides the functionality I need and in current debugging seems to be performant.
const messages = this.state.messages;
messages[index].pending = false;
messages[index].sent = true;
this.setState({ messages: GiftedChat.append(undefined, messages) });
The GiftedChat.append function appears to be a way to force a refresh of the state.
Is there any solution I am trying to update the message but it does happer any solution someone have found??
@charles-goode you are right, the message which is most recent only gets updated.
In my case, I am setting received to true. It fails to update all the messages list and it just updates the last message.received to true.
Here is the image:




Here is the code I am using for updating message:
preMarr[index].received = true;
if (this.mount) {
if (index === changed_IDArray.length - 1) {
this.setState(
{
messages: Array.from(preMarr),
},
() => {
// preMarr is the latest modified array
console.log('State in last ', this.state.messages);
},
);
}
}
If anyone found a solution then please suggest something.
I solved this issue, but I don't know if it is a perfect solution
preMarr[index].received = true;
if (this.mount) {
if (index === changed_IDArray.length - 1) {
this.setState(
{
messages: [], //<-----------------first set it to [ ] ,
},
() => {
this.setState({
messages: Array.from(preMarr), // <-------------- then in call back set it with updated array
});
console.log('State in last ', this.state.messages);
},
);
}
}
any suggestion is welcome.
Most helpful comment
I've been trying to implement message reactions similar to Facebook messenger, but on Android only the most recent message and the first message update properly when their props update. Like if I tap on a message to bring up the reaction bar, the reaction bar (which I implement as an absolute positioned view on top of my custom message bubble) will only render if its the top or most recent message.