React Firebase聊天应用无对应聊天文档时addMsg触发Unhandled Rejection错误
核心报错链梳理
1. 分支判断逻辑完全失效
chatExists是标记了async的异步函数,无论函数内部最终返回的chat.exists是true还是false,函数对外返回的永远是一个Promise对象。- 在JavaScript的布尔判断规则中,所有Promise对象都是真值,因此你在
submitForm中写的this.chatExists() ? this.goToExistChat() : this.createChat()判断,永远只会触发goToExistChat分支,根本不会走到预期的createChat分支打印'new chat'日志,这是整个错误的触发起点。
2. 空指针错误的连锁反应
- 当错误触发
goToExistChat分支后,父组件goToExistingChat方法中通过chats.find(...)匹配会话时,如果本地存储的chats状态数组里没有对应的会话,find方法会返回undefined。 - 代码没有对
find的返回值做存在性校验,直接对返回的undefined执行indexOf操作,会得到索引值-1。将这个值传给chooseChat后,组件状态里的selectedChat会被设置为-1。 - 进入
addMsg方法后,this.state.chats[this.state.selectedChat]实际等价于读取数组索引为-1的元素,这个值本身是undefined,后续尝试读取这个值上的users字段时,就会抛出Cannot read property 'users' of undefined的类型错误。
3. 附带的逻辑漏洞
- 拆分docKey提取好友邮箱的逻辑存在偏差:docKey是两个邮箱按字典序排序后用冒号拼接的字符串,
docKey.split(':')[1]取到的永远是字典序更大的邮箱,没有结合当前登录用户的账号做区分,可能导致匹配好友时邮箱取反。
修复方案
- 修正异步分支判断逻辑:将
submitForm改为async函数,通过await拿到chatExists的真实布尔返回值后再做分支判断,代码参考:
submitForm = async (e) => { e.preventDefault(); const chatIsExist = await this.chatExists(); chatIsExist ? this.goToExistChat() : this.createChat(); }
- 给会话查找逻辑加存在性中断,找不到匹配会话时直接触发新建流程,不继续执行后续发消息逻辑:
goToExistingChat = async (docKey, msg) => { // 修正好友邮箱提取逻辑:拆分两个邮箱后排除当前登录账号,剩下的就是好友邮箱 const [emailA, emailB] = docKey.split(':'); const friend = emailA === this.state.email ? emailB : emailA; const matchedChat = this.state.chats.find(chat => chat.users.includes(friend)); // 本地没有匹配的已存在会话时,直接中断流程走新建逻辑 if (!matchedChat) { this.createChat(); return; } const index = this.state.chats.indexOf(matchedChat); await this.chooseChat(index); this.addMsg(msg); }
- 给
addMsg增加取值防护,避免空指针报错:
addMsg = (msg) => { const currentSelectedChat = this.state.chats[this.state.selectedChat]; // 选中的会话不存在时直接中断,避免读取不存在字段报错 if (!currentSelectedChat) return; const friend = currentSelectedChat.users.filter(user => user !== this.state.email)[0]; const docId = this.buildDocId(friend); firebase.firestore().collection('chats').doc(docId).update({ messages: firebase.firestore.FieldValue.arrayUnion({ message: msg, sender: this.state.email, timestamp: Date.now() }) }); }
内容的提问来源于stack exchange,提问作者nataki
相关产品推荐
相关产品推荐

