Home > Blockchain >  How to update Firestore field called `likes`. I wanna plus or minus one
How to update Firestore field called `likes`. I wanna plus or minus one

Time:03-29

I have a question about how to update a number field in Cloud Firestore. I followed an official document and it was not that hard to write code. But it didn't work as I wanted. It seems like I didn't use async and await properly. I haven't perfectly understood async and await now, so no idea where I missed.

GoodBad.jsx

import { useState } from 'react';
import { FaHeart, FaRegHeart } from 'react-icons/fa';
// import { FaThumbsUp, FaRegThumbsUp } from "react-icons/fa";
import {updateDoc, getDoc, doc } from 'firebase/firestore';

import db from '../config/firebase';

const GoodBad = ({ quiz }) => {
  const [goodClicked, setGoodClicked] = useState(false);
  const [goodCounter, setGoodCounter] = useState(quiz.likes);

  // console.log(quiz.id, quiz.likes)

  const handleLikesUI = async (e) => {
    if (goodClicked === false) {
      setGoodClicked(true);
      setGoodCounter(prevState => prevState   1);
    } else {
      setGoodClicked(false);
      setGoodCounter(prevState => prevState - 1);
    }

    const docRef = doc(db, "quizzes", quiz.id)
    const payload = {likes: goodCounter}
    await updateDoc(docRef, payload);
  };


  return (
    <div className='quizFooter'>
      <div
        className={
          goodClicked
            ? 'likesCounterContainer checked'
            : 'likesCounterContainer'
        }
        onClick={() => handleLikesUI(quiz)}
      >
        <span className='heartIcon'>
          {goodClicked ? <FaHeart /> : <FaRegHeart />}{' '}
        </span>
        <span className='likesNumber'>{goodCounter}</span>
        {/* <span onClick={handleDislikes}>{goodClicked ? <FontAwesomeIcon icon="fa-regular fa-thumbs-down" /> : <FontAwesomeIcon icon="fa-solid fa-thumbs-down" />}bad: {badCounter}, {badClicked}</span> */}
      </div>
    </div>
  );
};

export default GoodBad;

CodePudding user response:

I would suggest using useEffect() for your use-case.

  useEffect(() => {
    const payload = {likes: goodCounter}
    updateDoc(docRef, payload)
  }, [goodCounter]);

  const handleLikesUI = async (e) => {
    if (goodClicked === false) {
      setGoodClicked(true);
      setGoodCounter(prevState => prevState   1);
    } else {
      setGoodClicked(false);
      setGoodCounter(prevState => prevState - 1);
    }
  };

On the code above, this will listen to changes of goodCounter in realtime and if there's change on the value of goodCounter, it will now proceed updating your document. If you wont use useEffect, there will be a delay when setting setGoodCounter.

As @mocherfaoui stated, if you want to just increment(or decrement) the existing value of a field, you must use increment. See sample code below:

if (goodClicked) {
   const n = 1
} else {
   const n = -1
}

updateDoc(docRef, {
    // `n` would be the number of increments (1 or -1).
    likes: increment(n)
});

For more information, you may check this documentation.

  • Related