reactjs - 如何将聊天中的加载图像替换为使用 ReactJS 上传到 Firebase 存储的图像?
问题描述
我已经使用 Firebase 和 ReactJS 建立了一个聊天室。我主要在https://firebase.google.com/codelabs/firebase-web#1关注他们的 Firebase 网络代码实验室. 但是,我一直卡在图像上传功能上。由于我使用的是 ReactJS,我不得不修改他们的纯 JS 代码以匹配我的。我能够在 Firestore 中保存带有“正在加载”图像 url 的消息,然后,我成功地保存了我想最终在 Firebase 存储中的聊天中显示的图像,最后我成功地从存储中检索了它的 url 并替换它使用 Firestore 中加载图像的 url。该图像确实显示在聊天中,但是,加载图像实际上并未被替换,而是当我希望它被完全替换时,它仍保留在聊天中,显然,因此加载图像不再存在。这就是我的意思,在这张图片中:
如您所见,顶部的加载图像保持不变,而不是被其下方的图像替换。我认为在我使用新图像 url 保存新快照之前,应该以某种方式将其过滤掉。但是,我无法弄清楚如何正确地做到这一点。我试图根据本地保存的加载图像的 url 将其过滤掉,但由于它在 Storage 中保存为 base64,所以它不起作用。也没有使用实际的 Base64 代码来过滤掉它。所以,我需要帮助来解决这个问题。codelab 并没有真正指定这一点,也不清楚他们是如何在纯 Javascript 代码中做到这一点的,而且我使用 ReactJS,所以它可能不是 100% 合适的。
我相信,这里有足够的代码来查看发生了什么。如果您需要更多,请告诉我。
以下是我将图像发送到聊天室的方式:(以 Firebase 代码实验室为模型)
sendImageToChat () {
this.state.chatFiles.forEach((file) => {
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) => {
this.setState({ writeError: error.message });
})
.then((messageRef) => {
// 2 - Upload the image to Cloud Storage.
const filePath = `users/${this.state.displayName}/${this.state.uid}/${moment().format("MMM Do YY")}/${uuidv4()}/${file.name}`
return firebase.storage().ref(filePath).put(file).then((fileSnapshot) => {
// 3 - Generate a public URL for the file.
return fileSnapshot.ref.getDownloadURL().then((url) => {
// 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 = "";
}
下面是我如何在添加加载图像以及修改其 url 时设置状态:(注意我如何尝试过滤掉加载图像的 loadingLogo 状态,但由于解释的原因,它显然不起作用多于)。
startChat () {
document.getElementById("myForm").style.display = "block";
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) => {
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("info saved"))
.catch((error) => {
console.log("Error saving info to document: ", error);
});
}
snapshot.docChanges().reverse().forEach((change) => {
if (change.type === 'removed') {
console.log(change.doc.data().content)
} else if (change.type === 'added') {
this.setState(state => {
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 => message.imageUrl !== loadingLogo)
console.log(filteredMessages)
this.setState(state => {
const messages = [...filteredMessages, {id: change.doc.id, body: change.doc.data()}]
return {
messages
}
})
setTimeout( this.scrollToBottom(), 2000)
}
});
}, (error) => {console.log(error)});
}
这是 Chat 的 JSX 的一部分:
<div className="chatArea" id='messages'>
{
this.state.messages.map((message, index) => {
return message.body.uid === this.state.uid
?
<div>
{
message.body.imageUrl ?
<img src={message.body.imageUrl} className="message-sent"></img>
:
<p className="message-sent" key={index}>{message.body.content}</p>
}
</div>
:
<p className="message-received" key={index}>{message.body.content}</p>
})
}
<div style={{ float:"left", clear: "both" }}
ref={(el) => { this.myRef = el; }}>
</div>
</div>
我知道问题不在于 Firebase,而在于 ReactJS。我知道我需要在使用新 url 的修改消息保存到状态之前或之后删除、过滤、替换或删除加载图像。所以,请帮我解决这个问题。相信很多人都会遇到这个问题。
谢谢!
解决方案
我想到了。我不妨删除这个问题,但它可能会帮助某人与 ReactJS 和 Firebase 建立聊天。无论如何,我根据对象属性过滤掉的方法 imageUrl 是一个可行的选择。有用!我愚蠢的疏忽是我没有在对象“消息”之后添加父属性或对象“body”。更具体地说,应该是 const filtersMessages = this.state.messages.filter(message => message.body.imageUrl 而不是 const filteredMessages = this.state.messages.filter(message => message.imageUrl !== loadingLogo ) !== loadingLogo)。您还可以尝试添加一个对象属性,您可以使用它来过滤掉消息,例如,允许:是或否。如果您需要更多说明,请问我,我很乐意提供帮助。快乐编码!
推荐阅读
- c# - 如何创建一个可以在场景>脚本>函数中选择对象的自定义检查器(公共无效...)
- python - 如何使用各种关闭机制从同步上下文中关闭异步循环
- laravel - 为当前用户重用用户资源路由
- javascript - 在表格中打印 For-Loop 结果
- tableau-api - 如何计算表格中今天平均销售额与昨天平均销售额的差异?
- r - 将长转换为宽时指定列顺序
- ios - 使用精灵速度(快速)飞扬的小鸟游戏旋转精灵
- arrays - 如何使用命名数组的接口:元素隐式具有“任何”类型,因为索引表达式不是“数字”类型
- python - 如何使用非 gmail 域名访问“gmail”伞形帐户?
- excel - Excel公式计算日期范围内的文本