title: How to replace a loading image in a chat with an image uploaded to Firebase Storage using ReactJS?
body: <p>I have built a chat using Firebase and ReactJS. I mainly followed their Firebase's web codelab at <a href="https://firebase.google.com/codelabs/firebase-web#1" rel="nofollow noreferrer">https://firebase.google.com/codelabs/firebase-web#1</a>. However, I have gotten stuck on the image uploading functionality. Since I am using ReactJS, I have had to modify their plain JS code to match mine. I am able to save a message with a &quot;loading&quot; image url in Firestore, then, I successfully save the image that I want to ultimately show in the chat in Firebase Storage, and finally then I successfully retrieve its url from Storage and replace it with the url of the loading image in Firestore. The image does show in the chat, however, the loading image is not actually replaced but, instead, it remains in the chat when I want it to be completely replaced, obviously, so that the loading image is no longer there. Here's what I mean, in this image:</p>
  <p><a href="https://i.stack.imgur.com/M4zIS.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/M4zIS.png" alt="enter image description here" /></a></p>
  <p>As you can see the loading image on top stayed on instead of being replaced by the image underneath it. I think it should be filtered out somehow before I save the new snapshot with the new image url. However, I can not figure out how to do it correctly. I tried to filter it out based on the url of the loading image which is saved locally but since it is saved as a base64 in Storage, it did not work. Neither did using the actual Base64 code as a way to filter it out. So, I need help to solve this issue. The codelab does not really specify this nor is it clear how they do it in their code which is in plain Javascript anyways and I use ReactJS so it may not be 100% suitable.</p>
  <p>Here's, I believe, enough code to see what is going on. Let me know if you need more of it.</p>
  <p>Here's how I send images to the Chat: (modeled on the Firebase codelab)</p>
  <pre><code>sendImageToChat () {
  
          this.state.chatFiles.forEach((file) =&gt; {
              firebase.firestore().collection('Chats')
              .doc(this.state.uid)
              .collection('Messages')  
              .add({
                  docId: this.state.docId,
                  imageUrl: loadingLogo,
                  timestamp: new Date(),
                  uid: this.state.uid,
                  name: this.state.displayName,
                  email: this.state.email
                  })
                  .catch((error) =&gt; {
                  this.setState({ writeError: error.message });
              })
              
              .then((messageRef) =&gt; {              
  
                  // 2 - Upload the image to Cloud Storage.
                  const filePath = `users/${this.state.displayName}/${this.state.uid}/${moment().format(&quot;MMM Do YY&quot;)}/${uuidv4()}/${file.name}`               
  
                  return firebase.storage().ref(filePath).put(file).then((fileSnapshot) =&gt; {
                    // 3 - Generate a public URL for the file.
                    return fileSnapshot.ref.getDownloadURL().then((url) =&gt; {
                      // 4 - Update the chat message placeholder with the image's URL.
                      return messageRef.update({
                        imageUrl: url,
                        storageUri: fileSnapshot.metadata.fullPath
                      });
                    });
                  });
                }).catch(function(error) {
                  console.error('There was an error uploading a file to Cloud Storage:', error);
                });
          })
  
          this.setState({
              chatFiles: []
          })
          document.getElementById('file-1').value = &quot;&quot;;
  
       }
  </code></pre>
  <p>Here's how I, then, setState when the loading image is added and then when its url is modified: (Notice how I try to filter out the loadingLogo which is the loading image out of the state but it does not obviously work for the reason explained above).</p>
  <pre><code>startChat () {    
  
      document.getElementById(&quot;myForm&quot;).style.display = &quot;block&quot;;       
     
      
          const ref = firebase.firestore().collection('Chats').doc(this.state.uid).collection('Messages');
  
          const query = ref.orderBy('timestamp', 'desc').limit(10)
  
  
  
          this.unsubFromMessages = query.onSnapshot((snapshot) =&gt; {                            
  
                              if (snapshot.empty) {
  
                                  console.log('No matching documents.');
                                  
                                  firebase.firestore().collection('Chats').doc(this.state.uid).
                                  set({
                                      name: this.state.displayName,
                                      uid: this.state.uid,
                                      email: this.state.email
                                  }).then(console.log(&quot;info saved&quot;))
                                  .catch((error) =&gt; {
                                      console.log(&quot;Error saving info to document: &quot;, error);
                                  });
                              }
                                                    
                                  snapshot.docChanges().reverse().forEach((change) =&gt; {                                  
                                    
  
                                  if (change.type === 'removed') {
                      
                                  console.log(change.doc.data().content)
                      
                                  } else if (change.type === 'added') {                
                                  
                                    this.setState(state =&gt; {
                                      const messages = [...state.messages, {id: change.doc.id, body: change.doc.data()}]
                                      return {
                                          messages
                                      }
                      
                                  })    
                                  
                                  setTimeout( this.scrollToBottom(), 2000)
                                  
                                  
                                  
                                  } else if (change.type === 'modified') { 
                                      
                                                                          
                                      const filteredMessages = this.state.messages.filter(message =&gt; message.imageUrl !== loadingLogo)
  
                                      console.log(filteredMessages)
  
                                      this.setState(state =&gt; {
                                        const messages = [...filteredMessages, {id: change.doc.id, body: change.doc.data()}]
                                        return {
                                            messages
                                        }
                        
                                    })    
                                    
                                    setTimeout( this.scrollToBottom(), 2000)
                                    
                                    
                                    
                                    } 
                      
                                  
                                  });
                                  }, (error) =&gt; {console.log(error)});             
                      
  
      }
  </code></pre>
  <p>This is part of the Chat's JSX:</p>
  <pre><code> &lt;div className=&quot;chatArea&quot; id='messages'&gt;
                              
                         
                              {
                                 
                                  this.state.messages.map((message, index) =&gt; {
                                  return message.body.uid === this.state.uid 
                                  ?
                                  &lt;div&gt;
                                  {
                                  message.body.imageUrl ? 
                                  &lt;img src={message.body.imageUrl} className=&quot;message-sent&quot;&gt;&lt;/img&gt;
                                  :
                                  &lt;p className=&quot;message-sent&quot; key={index}&gt;{message.body.content}&lt;/p&gt;
                                  }
                                  &lt;/div&gt;
                                 
                                  :
                                  &lt;p className=&quot;message-received&quot; key={index}&gt;{message.body.content}&lt;/p&gt;
                                  })
                              
                              }                           
                             
  
                          &lt;div style={{ float:&quot;left&quot;, clear: &quot;both&quot; }}
                                 ref={(el) =&gt; { this.myRef = el; }}&gt;
                              &lt;/div&gt;
  
                          &lt;/div&gt;
  </code></pre>
  <p>I know the issue is not with Firebase but rather with ReactJS. I know I need to remove, filter out, replace or delete that loading image before or after the modified message with the new url is saved to the state. So, please help me figure this out. I am sure many people may encounter this problem.</p>
  <p>Thank you!</p>