'how to set ID for every bubble message and then update using its ID

Easy way to understand what is my question play the following video and see what is my problem. https://vimeo.com/315390850

if you dont have a good inernet connection then read the following sentences.

I am going to update bubble messages but i dont know how to update specific message by Id. Example: in html there is and Id for every tag within a list and if we have to update then we select it by id and then update it. So how to make a concept like that for react-native-gifted-chat bubble messages?

I tried to use refs with setNativeProps function but did not work.

render(){
 return (
   <GiftedChat
         extraData={this.state}
         messages={this.state.messages}
          onSend={messages => this.onSend(messages)}
          user={{
              _id: this.state.userId,
           }}
           renderBubble={this.renderBubble}
           renderInputToolbar={this.renderInputToolbar.bind(this)}
      />
 );
}

renderBubble = props => {
        if (props.currentMessage.audio) {
            return (
                <View style={[{ width: 150, height: 70, backgroundColor: 'lightgray' }, props.position === 'left' ? { left: -41 } : {}]}>
                    <EIcon
                        name="google-play"
                        size={30}
                        color={this.state.playAudio ? "red" : "blue"}
                        style={{
                            left: 90,
                            position: "relative",
                            shadowColor: "#000",
                            shadowOffset: { width: 0, height: 0 },
                            shadowOpacity: 0.5,
                            backgroundColor: "transparent"
                        }}
                        onPress={() => {
                            this.setState({
                                playAudio: true
                            });
                            const sound = new Sound(props.currentMessage.audio, "", error => {

                                if (error) {
                                    console.log("failed to load the sound", error);
                                }

                                const duration = sound.getDuration();
                                const progressPhase = 1 / duration;

                                if (duration !== 0) {
                                    this._interval = setInterval(() => {

                                        this.setState({
                                            progress: this.state.progress += progressPhase
                                        });

                                        if (this.state.progress >= 1) {
                                            clearInterval(this._interval);
                                            this.setState({
                                                progress: 0.0,
                                                playAudio: false
                                            });
                                        }

                                    }, 1000);
                                }

                                sound.play(success => {
                                    console.log(success, "success play");
                                    if (!success) {
                                        Alert.alert("There was an error playing this audio");
                                    }
                                });

                            });
                        }}
                    />


                    <Progress.Circle progress={this.state.progress} showsText size={35} />

                </View>
            );
        } else {
            return (
                <Bubble
                    {...props}
                    textStyle={{
                        right: {
                            color: '#fff',
                        },
                        left: {
                            color: '#fff',
                        },
                    }}
                    wrapperStyle={{
                        left: {
                            backgroundColor: "orange",
                            left: -41
                        },
                        right: {
                            backgroundColor: 'green'
                        }
                    }}
                />
            );
        }
    }

Here I have a chatbox when I send multiple audio message for example 3 aduio message: audio message .1, audio message .2, audio message .3 aduio message .1 has came first time. aduio message .3 has came last time.

every audio message has a play icon and a progressbar. When I click on play Icon, then I update the progressbar. here I used interval for one click on play icon, the progressbar gets update multiple time until gets complete.

My Problem is: when i click the play icon of audio message .1 just the last audio message .3 gets updated. I want: if I click on audio message .1 the progressbar of audio message .1 should be update. same for audio message .2 and audio message .3.



Solution 1:[1]

I solved my problem by conditional rendering Also I changed following class and I added this line: next.audio == current.audio ||

export default class Message extends React.Component {

  shouldComponentUpdate(nextProps) {
    const next = nextProps.currentMessage;
    const current = this.props.currentMessage;
    const { nextMessage } = this.props;
    const nextPropsMessage = nextProps.nextMessage;
    return (
      next.send !== current.send ||
      next.received !== current.received ||
      next.pending !== current.pending ||
      next.createdAt !== current.createdAt ||
      next.text !== current.text ||
      next.image !== current.image ||
      next.video !== current.video ||
      next.audio == current.audio ||  // this line added by me
      nextMessage !== nextPropsMessage
    );
  }

 //..............

}

I add this condition and please please let me know about performance. this tree line, I added to my code:

this.myPro = <Progress.Circle progress={this.state.progress} showsText size={35} />; this.setState({currentPlayedMessage: props.currentMessage._id }); { props.currentMessage._id === this.state.currentPlayedMessage ? this.myPro : null }

All code:

if (props.currentMessage.audio) {

            this.myPro = <Progress.Circle progress={this.state.progress} showsText size={35} />; // this line added

            return (
                <View style={[{ width: 150, height: 70, backgroundColor: 'lightgray' }, props.position === 'left' ? { left: -41 } : {}]}>
                    <EIcon
                        name="google-play"
                        size={30}
                        color={this.state.playAudio ? "green" : "blue"}
                        style={{
                            left: 90,
                            position: "relative",
                            shadowColor: "#000",
                            shadowOffset: { width: 0, height: 0 },
                            shadowOpacity: 0.5,
                            backgroundColor: "transparent"
                        }}
                        onPress={() => {

                            this.setState({
                                playAudio: true,
                                currentPlayedMessage: props.currentMessage._id // this line added
                            });

                            const sound = new Sound(props.currentMessage.audio, "", error => {

                                if (error) {
                                   return;
                                }

                                const duration = sound.getDuration();
                                const progressPhase = 1 / duration;

                                if (duration !== 0) {
                                    this._interval = setInterval(() => {

                                        this.setState({
                                            progress: this.state.progress += progressPhase
                                        });

                                        if (this.state.progress >= 1) {
                                            clearInterval(this._interval);
                                            this.setState({
                                                progress: 0.0,
                                                playAudio: false
                                            });
                                        }

                                    }, 1000);
                                }

                                sound.play(success => {
                                    console.log(success, "success play");
                                    if (!success) {
                                        Alert.alert("There was an error playing this audio");
                                    }
                                });

                            });
                        }}
                    />


                    { props.currentMessage._id === this.state.currentPlayedMessage ? this.myPro : null } // this line added

                </View>
            );
        }

Solution 2:[2]

i was getting the same issue but i solved it like this in functional component. first you add shouldUpdateMessage in gifted chat component

 <GiftedChat
     messages={messages}
      onSend={messages => onSend(messages)}
       renderBubble={renderBubble}
       renderInputToolbar={renderInputToolbar.bind(this)}
       shouldUpdateMessage={(props, nextProps) => { return props.currentMessage.audio == nextProps.currentMessage.audio ? true : false }}        // Add this in your gifted chat

  />

Then i solved it like this in the render method, i've just used my code but you can just follow the same method.

if (currentMessage.audio) {
       
        const icon=        <Icon key={currentMessage.key} name={'play-arrow'} size={30} type="material" color={ 'blue'} />
        const icon2=        <Icon key={currentMessage.key} name={'multitrack-audio' } size={30} type="material" color={'red'} />
        
        return (
            <TouchableOpacity key={currentMessage.key} onPress={() => {
                setCurrentPlayedMessage(currentMessage.key)

            }} >
               { props.currentMessage.key === currentPlayedMessage ? icon2: icon }     //This Line is responsible for changing a specific message, you can use your component in ternary operator after condition
            </TouchableOpacity>
        )
    }
    
    return (
        <Bubble

            {...props} />

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Iqbal Jan
Solution 2 Ali Turab