Skip to content

Bubble component does not rerender when updating messages #2589

Closed
@DimaIvashchuk

Description

@DimaIvashchuk
  • Expo SDK: 52.0.26
  • React Native: 0.76.7
  • react-native-gifted-chat: 2.7.3
  • @shopify/flash-list: ^1.7.3
  • react-native-reanimated: ~3.10.1
  • react-native-keyboard-controller: ^1.16.4
  • Platform: iOS

Hello,
after updating to latest version of react-native-gifted-chat from 2.6.3 My message bubble stops re-rendering on message update

My steps to reproduce:

  1. Sending message
const _newMessages = GiftedChat.append(messages, sentMessages, Platform.OS !== 'web');

        setMessages(_newMessages);
        mutate({ chatId: id, text: newMessages[0].text, id: newMessages[0]._id as string });
  1. on successful response I am updating message's pending and sent status
setMessages((prev) =>
        prev.map((message) =>
          message._id === data.id ? { ...message, pending: false, sent: true } : message,
        ),
      );
  1. Message appears on the screen with pending status but does not rerenders even so I can see in the console that messages (state) has been updated and passed to GiftedChat, but MessageBubble component does not re renders

My implementaton:

<View style={{ flex: 1, paddingHorizontal: 16 }}>
          <GiftedChat
            text={text}
            onInputTextChanged={(text) => setText(text)}
            renderLoading={() => <ActivityIndicator />}
            messages={messages}
            // messageContainerRef={flatListRef}
            inverted={Platform.OS !== 'web'}
            infiniteScroll
            keyboardShouldPersistTaps="always"
            onSend={onSend}
            locale={i18n.language}
            isScrollToBottomEnabled
            onLongPress={(context, message) => {
              const options = [
                t('bubbleActions.copy'),
                t('bubbleActions.edit'),
                t('bubbleActions.cancel'),
              ];
              const cancelButtonIndex = options.length - 1;
              showActionSheetWithOptions(
                {
                  options,
                  cancelButtonIndex,
                },
                async (buttonIndex) => {
                  switch (buttonIndex) {
                    case 0:
                      await Clipboard.setStringAsync(message.text);
                      break;

                    case 1:
                      setText(message.text);
                      setEditMessage({ id: message._id.toString(), text: message.text });
                      break;
                  }
                },
              );
            }}
            messageIdGenerator={() => uuid()}
            listViewProps={{
              // @ts-ignore
              onViewableItemsChanged: onViewItemsChange,
              viewabilityConfig: {
                waitForInteraction: true,
                itemVisiblePercentThreshold: 90,
              },
            }}
            loadEarlier={!!nextCursor}
            onLoadEarlier={onLoadEarlier}
            isLoadingEarlier={isLoadingEarlier}
            user={{
              _id: me.id,
              name: me.displayName,
              avatar: me.avatarUrl,
            }}
            onPressAvatar={onAvatarPress}
            messagesContainerStyle={{ paddingVertical: 16, paddingHorizontal: 0 }}
            renderSend={(props) => (
              <Send
                {...props}
                containerStyle={{
                  marginRight: 16,
                  marginLeft: 8,
                  alignContent: 'center',
                  justifyContent: 'center',
                }}>
                <images.send color={Colors.electric[400]} width={24} height={24} />
              </Send>
            )}
            renderUsernameOnMessage={chatDetails.isGroup}
            renderTime={(props) => (
              <Time
                {...props}
                timeTextStyle={{
                  left: {
                    color: Colors.gray[400],
                    ...ThemedTextStyles['xxs.regular'],
                  },
                  right: {
                    color: Colors.gray[400],
                    ...ThemedTextStyles['xxs.regular'],
                  },
                }}
              />
            )}
            renderInputToolbar={(props) => (
              <View style={{ flexDirection: 'column' }}>
                {editMessage && (
                  <View style={styles.editContainer}>
                    <images.pencil color={Colors.gray[400]} />
                    <View style={styles.editInnerContainer}>
                      <ThemedText type="xxs.medium">{t('bubbleActions.edit')}</ThemedText>
                      <ThemedText type="xxs.regular">{editMessage.text}</ThemedText>
                    </View>
                    <IconButton
                      icon="xIxon"
                      onPress={() => {
                        setEditMessage(null);
                        setText('');
                      }}
                    />
                  </View>
                )}

                <InputToolbar
                  {...props}
                  containerStyle={{
                    borderRadius: 16,
                    borderWidth: 1,
                    borderTopWidth: 1,
                    borderTopColor: Colors.gray[200],
                    borderColor: Colors.gray[200],
                  }}
                />
              </View>
            )}
            renderUsername={(props) => (
              <ThemedText color="secondary" type="xxxs.medium">
                ~ {props.name}
              </ThemedText>
            )}
            scrollToBottomStyle={{ opacity: 1 }}
            scrollToBottomComponent={() => <images.caretDown color={Colors.gray[400]} />}
            renderBubble={(props) => <BubbleMessage {...props} />}
            timeTextStyle={{
              left: { color: Colors.gray[400] },
              right: { color: Colors.gray[400] },
            }}
            {...(!chatDetails.isGroup && { renderAvatar: null })}
          />
          {Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />}
        </View>

import { Colors } from '@/constants/Colors';
import { images } from '@/constants/images';
import { withTheme } from '@rneui/themed';
import { View } from 'react-native';
import { Bubble, BubbleProps, IMessage, Time } from 'react-native-gifted-chat';

export type BubbleMessageProps = BubbleProps<IMessage>;

const BubbleMessage = (props: BubbleMessageProps) => {
  console.log(
    'BubbleMessage',
    props.currentMessage.text,
    props.currentMessage.pending,
    props.currentMessage.sent,
    props.currentMessage.received,
  );
  return (
    <Bubble
      {...props}
      renderTime={(props) => (
        <>
          {props.currentMessage.edited && (
            <images.pencil color={Colors.gray[500]} width={12} height={12} />
          )}
          <Time
            {...props}
            containerStyle={{
              left: {
                marginBottom: 0,
                marginLeft: 0,
                marginRight: 0,
                marginTop: 1,
                justifyContent: 'center',
              },
              right: {
                marginBottom: 0,
                marginLeft: 0,
                marginRight: 0,
              },
            }}
          />
        </>
      )}
      renderTicks={(message) => {
        if ((message.sent || message.received || message.pending) && props.position === 'right') {
          return (
            <View style={{ flexDirection: 'row', alignItems: 'center' }}>
              {message.pending ? (
                <images.clock color={Colors.gray[500]} width={12} height={12} />
              ) : (
                <>
                  <images.checkIcon color={Colors.electric[400]} width={12} height={12} />
                  {message.received && (
                    <images.checkIcon
                      color={Colors.electric[400]}
                      width={12}
                      height={12}
                      style={{
                        marginLeft: -8,
                      }}
                    />
                  )}
                </>
              )}
            </View>
          );
        }
      }}
    />
  );
};

export default withTheme<BubbleMessageProps>(BubbleMessage, 'BubbleMessage');

This is my first issue so if i missed smthn please tell me

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions