所以,我正在尝试使用 Firebase 用 React 创建一个评论部分。
数据库结构如下:
“项目”页面的代码为:
import React , { useEffect, useState, useRef }from 'react'
import firebase from "firebase/app";
import "firebase/database";
import { useAuth } from '../contexts/AuthContext'
export default function ProjectPage(props) {
const { currentUser } = useAuth()
const [author, setAuthor] = useState({})
const commentRef = useRef()
const[comments, setComments] = useState([])
const [loadingComment, setLoadingComment] = useState(0)
useEffect(()=>{
retrieveAuthor();
retrieveComments()
console.log(currentUser.uid)
}, [loadingComment])
function retrieveAuthor(){
if(props.location.project){
var user = firebase.database().ref('/users/'+props.location.project.uid)
user.once('value', (snapshot) => {
setAuthor({name: snapshot.val().name, surname: snapshot.val().surname})
})
}
}
function retrieveComments(){
if(props.location.project){
var comments = firebase.database().ref('/projects/'+props.location.project.uid + '/' + props.location.project.pid+'/comments');
comments.once('value', (snapshot)=>{
snapshot.forEach((snap)=>{
const commentObj = snap.val()
setComments(comments => [...comments, commentObj])
console.log(comments)
})
})
}
}
const handleSubmit = (e) =>{
e.preventDefault()
firebase.database().ref('/projects/'+ props.location.project.uid + '/' + props.location.project.pid +'/comments/').push({
author: currentUser.uid,
comment: commentRef.current.value
})
commentRef.current.value = ''
setLoadingComment(loadingComment + 1)
}
if(! props.location.project){
return <div>No project selected</div>
}else {
return (
<div>
<h1><strong>{props.location.project.title}</strong></h1>
<div className='row w-100 h-100'>
<div className='col card m-3 ml-4 p-3'>
<div className='row text-center align-item-center mx-auto'>Comment Section</div>
<div className='card'>
{comments && comments.map(comment=>{
console.log(comment)
return <div>{comment.comment}</div>
})}
</div>
<form onSubmit = {handleSubmit}>
<div className="input-group mb-3">
<input ref= {commentRef} type="text" className="form-control" placeholder="Your comment..." aria-label="Recipient's username" aria-describedby="basic-addon2"/>
<div className="input-group-append">
<button className="btn btn-outline-secondary">Add</button>
</div>
</div>
</form>
</div>
<div className='col-9'>
<div className = 'row'>
<div className='col'><strong>Description: </strong>{props.location.project.description}</div>
<div className='col'><strong>Author: </strong>{author.name} {author.surname}</div>
</div>
<div className='row card text-center align-item-center '>
<img className=' mx-auto w-100 h-100' src={props.location.project.url} />
</div>
</div>
</div>
</div>
)}
}
基本上发生的事情是:
它只是再次加载已经加载的评论!
我在调用retrieveComments/useEffect/handleSubmit时试图清空评论状态但没有用,我不知道发生了什么:(
答案 0 :(得分:1)
当您在 Firebase 中监听某个值时,每次调用您的回调时,它都会获取该位置所有数据的完整快照。因此,预计第二次,您会收到新消息 ** 以及已经存在的所有消息。
所以你需要忽略状态中comments
的当前值,并且总是只使用数据库中的信息来填充它:
function retrieveComments(){
if(props.location.project){
var comments = firebase.database().ref('/projects/'+props.location.project.uid + '/' + props.location.project.pid+'/comments');
comments.once('value', (snapshot)=>{
let msgs = [];
snapshot.forEach((snap)=>{
msgs.push(snap.val());
})
setComments(comments => msgs);
})
}
}
顺便说一句:我建议使用 on()
(而不是 once()
),因为这意味着 Firebase 将继续监听数据库的更改,并在有人发布或编辑评论时自动更新评论。