React中点击Firebase Firestore文档如何获取ID实现帖子删除
问题根因
你遇到的Uncaught TypeError: Cannot read properties of undefined (reading 'indexOf')报错,核心原因是调用deleteDoc(doc(db, "posts", id))时,第三个参数id是undefined。Firestore SDK内部会对文档路径字符串调用indexOf方法做校验,传入undefined就会直接抛出这个错误。
虽然你在useCollectionData里配置了idField: "id",期望自动把文档ID挂到返回的post对象上,但这种隐式挂载的方式容易因为字段重名、数据加载时序问题出现取值失败,最稳妥的方案是渲染列表时显式传递文档ID。
修复步骤
1. 修改Feed组件,显式传递文档ID
把列表渲染时的Post组件调用,单独传入文档ID作为独立prop,避免从post对象解构取值的异常:
function Feed() { const postsRef = collection(db, 'posts'); const qwery = query(postsRef,orderBy('createdAt'), limitToLast(25)); const [posts] = useCollectionData(qwery, {idField: "id"}); return ( <main> {posts && posts.map(msg => ( // 显式把文档ID作为postId prop传入,不依赖post对象里的id字段 <Post key={msg.id} postId={msg.id} post={msg} /> ))} </main> ) }
2. 修改Post组件,简化删除逻辑
去掉从post对象里解构id的代码,直接从props取传入的postId,同时简化冗余的DOM嵌套,去掉没必要的stopPropagation(你的帖子卡片没有绑定父级点击事件,不需要阻止冒泡),可以加上简单的错误捕获避免静默失败:
function Post(props) { // 从props拿显式传入的postId,不要从post里解构id const { postId, post } = props; const {text, photoURL, displayName, uploaderId} = post; // 抽离删除逻辑,结构更清晰 const handleDelete = async (e) => { // 二次权限校验,避免异常状态下的误调用 if (auth.currentUser?.uid !== uploaderId) return; try { await deleteDoc(doc(db, "posts", postId)); } catch (err) { console.error("删除失败:", err); alert("帖子删除失败,请重试"); } } return ( <div className="post"> <div className='msg'> <div className='top'> <img src={photoURL} alt="" /> <sub>{displayName}</sub> </div> <hr /> <p>{text}</p> {auth.currentUser?.uid === uploaderId ? ( // 直接把点击事件绑在按钮上,不需要多余的div嵌套 <button onClick={handleDelete} className="delete-btn">🗑️</button> ) : null} </div> </div> ) }
额外优化建议
- 前端的权限判断只是视觉隐藏,必须搭配Firestore安全规则做后端权限校验,否则其他人可以绕过前端直接调用接口删除任意帖子,规则参考:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /posts/{postId} { allow read: if true; allow create: if request.auth != null && request.resource.data.uploaderId == request.auth.uid; // 仅帖子上传者本人可以删除/修改帖子 allow delete, update: if request.auth != null && resource.data.uploaderId == request.auth.uid; } } }
- 可以在删除前加
confirm("确认删除这篇帖子?")二次确认,避免用户误点。
内容的提问来源于stack exchange,提问作者cavia cavia
相关产品推荐
相关产品推荐

