简体   繁体   English

useState 未更新 useEffect 中的初始值

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM