React.js结合Firebase Firestore做实时聊天发消息返回ID而非内容
根因定位
Array.map回调参数顺序写反:map第一个参数为当前遍历元素、第二个为索引,原代码反向命名后,传给子组件的key是消息对象、msg是数字索引,逻辑完全错乱- 消息状态类型混杂:
sendMessage中手动往messages数组追加原始输入字符串,和Firebase同步返回的{id, message}对象结构不统一,最终触发React无法渲染对象的报错 - 数据嵌套层级冗余:Firebase中存储的消息结构为
{message: 输入文本},原代码取数时额外套了一层message字段,形成{id: "xxx", message: {message: "文本"}}的双层嵌套,直接传对象到子组件就会触发渲染报错 - 滚动逻辑属性错误:DOM元素无
scrollBottom属性,使用非标准属性无法实现自动滚到底部的效果 - 冗余状态更新:Firebase的
onSnapshot会自动同步新写入的消息,手动重复调用setMessages会导致状态和数据库不一致
修复后核心代码
import React, { useEffect, useState } from "react"; import db from "../firebase"; import Message from "./Message"; import "../styles/Chat.css"; const Chat = () => { const [input, setInput] = useState(""); const [messages, setMessages] = useState([]); // 监听Firebase消息,拉平嵌套结构 useEffect(() => { db.collection("messages") .orderBy("createdAt", "asc") // 按发送时间排序,可选优化 .onSnapshot((snapshot) => { setMessages( snapshot.docs.map((doc) => ({ id: doc.id, text: doc.data().message })) ); }); }, []); const sendMessage = (event) => { event.preventDefault(); // 空内容直接拦截,避免无效提交 if (!input.trim()) return; db.collection("messages").add({ message: input, createdAt: new Date() // 配套排序用的时间字段,可选 }); setInput(""); }; const scrollToMessage = () => { const chat = document.querySelector("#messages"); if (!chat) return; // 修正为标准DOM属性,设置滚动高度实现自动到底 chat.scrollTop = chat.scrollHeight; }; useEffect(() => { scrollToMessage(); }, [messages]) return ( <div className="chat-card overflow-y-scroll shadow-md mx-auto p-5 w-10/12 h-4/6 my-24"> <h1 className="text-white text-center font-bold text-lg"> Community Chat </h1> <div className="my-5 mx-auto"> <form onSubmit={sendMessage}> <input value={input} onChange={(event) => setInput(event.target.value)} className="w-full py-2 rounded" type="text" /> <button className="w-full text-white font-bold my-2 rounded bg-red-500 py-2"> SEND </button> </form> </div> <div id="messages" className="messages"> { messages.map((msgItem) => ( <Message key={msgItem.id} msg={msgItem.text} /> )) } </div> </div> ); }; export default Chat;
关键修改说明
- 取数时直接提取Firebase存储的文本内容作为
text字段,去掉多余的对象嵌套 - 删除
sendMessage里手动更新messages的逻辑,完全依赖Firebase快照自动同步,避免状态类型不一致 - 修正
map回调的参数命名,使用消息唯一id作为React列表key,传给子组件的msg为纯文本内容 - 修正滚动逻辑的DOM属性,使用标准
scrollTop属性实现自动滚动到底部 - 新增空内容校验和时间戳字段,优化消息发送和排序逻辑
内容的提问来源于stack exchange,提问作者Caleb
相关产品推荐
相关产品推荐

