[英]useState is not updating initial value in useEffect
I am working on like functionality for my web-app.我正在为我的网络应用程序开发类似的功能。 The problem here is my setLike is not changing the state even after using setLike(.like).
这里的问题是我的 setLike 没有改变 state 即使在使用 setLike(.like) 之后。 I checked this with console.log() by using it before and after the setlike() but both the console.log() statements were giving me the same value.
我通过在 setlike() 之前和之后使用 console.log() 进行了检查,但是两个 console.log() 语句都给了我相同的值。 Here is my Post component.
这是我的 Post 组件。
import React , {useState,useEffect} from 'react'
import './Post.css'
import Avatar from '@material-ui/core/Avatar';
import {Button, IconButton, Input, Typography } from '@material-ui/core';
import {DataBase} from './firebase'
import firebase from 'firebase';
import FavoriteIcon from '@material-ui/icons/Favorite';
import {useStateValue} from '../contexts/StateProvider'
function Post({postId}) {
//get the user from the provider
const [{user}, dispatch] = useStateValue();
//number of likes
const [likeCount,setLikeCount] = useState(likesCount)
//if like=true or not
const [like, setLike] = useState(false);
I am using firebase firestore database for backend.我正在使用 firebase firestore 数据库作为后端。 The like document only exists in the database collection when the user interacts with it for the first time (likes it or likes it first and then does undo like).
当用户第一次与它交互时,like 文档仅存在于数据库集合中(喜欢它或先喜欢它然后撤消喜欢)。 So first check whether user previously liked the document or not.
所以首先检查用户以前是否喜欢该文档。 If user previously liked the document, then get the value of the like for that particular user (true/false) and set it using setLike(like).
如果用户以前喜欢该文档,则获取该特定用户的 like 值(true/false)并使用 setLike(like) 设置它。 Also get the number of documents in the collection who have like==true and set it equal to setLikeCount(likeCount).
还获取集合中具有like==true 的文档数,并将其设置为等于setLikeCount(likeCount)。
//=======Get likes from the database ===========================
useEffect(() => {
//check if the user already liked the doc or not (first time or not)
DataBase.collection('posts').doc(postId).collection('postLikes')
.doc(user.uid).get().then((doc) => {
if (doc.exists) {
console.log(doc.data().like)
//set like to value of like from database
setLike(doc.data().like)
} else {
// doc.data() will be undefined in this case
console.log("Not liked");
}
}).catch((error) => {
console.log("Error getting document:", error);
});
//grab the docs which have like=true
DataBase.collection('posts').doc(postId).collection('postLikes').where("like", "==",
true).get()
.then((querySnapshot) => {
setLikeCount((querySnapshot.docs.map(doc =>doc.data())).length)
console.log(likeCount +" likes count")
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}
//when postId changes or page loads fire the code above
},[postId])
Here is my postLike function.这是我的帖子,例如 function。 The setLike(.like) is supposed to toggle the previous like value the user has for the document from firebase.
setLike(.like) 应该从 firebase 切换用户对文档的先前相似值。 I guess this is not updating.
我想这不是更新。
//=============Post likes to the database=======
const postLike = (e) => {
//if already liked i.e. doc exists
console.log(like+"like before")
setLike(!like)
console.log(like+"like after")
like?(setLikeCount(likeCount+1)):(setLikeCount(likeCount-1))
console.log("likeCount"+likeCount)
DataBase.collection('posts').doc(postId).collection('postLikes').doc(user.uid).set(
{
like:like,
username:user.displayName,
timestamp:firebase.firestore.FieldValue.serverTimestamp(),
}
).catch((err)=>{console.log("something wrong happened "+err.message)})
}
return (
<div className="post">
<div className="post__likes">
{/*like button*/}
{
like?
(<Button onClick={postLike} ><FavoriteIcon fontsize="small" cursor="pointer" onClick=.
{postLike} style={{color:'red'}}/></Button> ):
(<Button onClick={postLike} ><FavoriteIcon fontsize="small" cursor="pointer" />
</Button>)
}
<Typography style={{color:'aliceblue'}}>Liked by {likeCount}</Typography>
</div>
</div>
)
}
export default Post
Edit:编辑:
Yeah, the useEffect
might have been a bad idea.是的,
useEffect
可能是个坏主意。 It's getting called on initial load and after like
is updated from the server request.它在初始加载时被调用
like
并且在从服务器请求更新之后。 I've made a snippet that I think does most of what you want.我制作了一个片段,我认为它可以满足您的大部分需求。 It's still brittle though because a user can click the
like
button before we get back the likeCount
from the server.但它仍然很脆弱,因为用户可以在我们从服务器取回
likeCount
之前单击like
按钮。 You might want to disable the button while the request is pending.您可能希望在请求挂起时禁用该按钮。
const { useState, useEffect } = React; function Post({ postId }) { //number of likes const [likeCount, setLikeCount] = useState(5) //if like=true or not const [like, setLike] = useState(false); //=======Get likes from the database =========================== useEffect(() => { // This is a call to the server to check if the user already liked the doc or not (first time or not) setTimeout(() => { if (true) { setLike(true); } }, 500); // This is a call to the server to grab the docs which have like=true setTimeout(() => { setLikeCount(15); }, 400); //when postId changes or page loads fire the code above }, [postId]); //=============Post likes to the database======= const postLike = (e) => { //if already liked ie doc exists const newLikeValue =;like? const newLikeCount = like: likeCount - 1; likeCount + 1; setLike(;like); setLikeCount(newLikeCount). setLike(newLikeValue). // Update like value on server here /* DataBase.collection('posts').doc(postId).collection('postLikes').doc(user:uid),set({ like: newLikeValue. // <-- Use newLikeValue here username, user:displayName. timestamp. firebase.firestore,FieldValue.serverTimestamp(). }).catch((err) => { console?log("something wrong happened " + err:message) }) */ } return ( <div className = "post" > <div className = "post__likes" > { /*like button*/ } { like: (<button onClick={postLike}><div style={{color;'red'}}>Icon here</div></button>). (<button onClick={postLike}><div>Icon here</div></button>) } <p>Liked by {likeCount}</p> </div> </div> ), } ReactDOM.render( <Post postId={5}/>; document.getElementById("react") );
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="react"></div>
Initial answer:初步答案:
Personally, I would use a local copy as Dave suggested in a comment.就个人而言,我会使用 Dave 在评论中建议的本地副本。 But you could also set up another
useEffect
to listen for changes to like
and make your server update inside there.但是您也可以设置另一个
useEffect
来监听更改以使like
的服务器在里面更新。
useEffect(() => {
like?(setLikeCount(likeCount+1)):(setLikeCount(likeCount-1));
DataBase
.collection('posts').doc(postId)
.collection('postLikes').doc(user.uid)
.set(
{
like:like,
username:user.displayName,
timestamp:firebase.firestore.FieldValue.serverTimestamp(),
}
).catch((err)=>{console.log("something wrong happened "+err.message)})
}, [like]);
const updateLike = (e) => {
setLike(!like);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.