Este es el código de un componente que creé que se carga en algunas tarjetas que muestran datos. Este componente carga los datos de esa tarjeta (sale_id) y se utiliza para almacenar en la base de datos.
import { LikeButtonStyle } from './LikeButton.styled'; import { Image } from '../../styles/index.styled'; import { useEffect, useState } from 'react'; import { useAuthContext } from '../Provider'; import { setDoc, doc, getDoc } from 'firebase/firestore'; import { db } from '../../firebase/clientApp'; function UserLikeButton(sale_id) { const { currentUser } = useAuthContext(); var [userLikes, setUserLikes] = useState('no'); var [user, setUser] = useState(currentUser.actor); const [likeCount, setLikeCount] = useState('0'); const id = sale_id.sale_id; const userCollectionRef = doc(db, 'Feed Posts', id); async function getUserData() { const docSnap = await getDoc(userCollectionRef); if (docSnap.exists()) { setUser(docSnap.data().username); setUserLikes(docSnap.data().likePost); if (userLikes === 'no') { setLikeCount('0'); } else { setLikeCount('1'); } } } useEffect(() => { getUserData(); }, ); const addInfoToDataBase = async () => { await setDoc(userCollectionRef, { likePost: userLikes, username: user, }); }; function likeUnlike() { if (userLikes === 'no') { setUserLikes('yes'); setLikeCount('1'); addInfoToDataBase(); } else { setUserLikes('no'); setLikeCount('0'); addInfoToDataBase(); } } if (!currentUser) { return ( <LikeButtonStyle> <Image width="10px" height="auto" src="/like-svgrepo-com.svg"></Image> <> {userLikes} </> </LikeButtonStyle> ); } else { return ( <> <LikeButtonStyle onClick={likeUnlike}> <Image width="10px" height="auto" src="/like-svgrepo-com.svg"></Image> <> {likeCount} </> </LikeButtonStyle> </> ); } } export default UserLikeButton;La lógica que tengo es que en la base de datos, cada publicación (sale_id) contiene un usuario y su decisión de que le guste un elemento que se almacena como userLike. Uso useEffect para cargar lo que sea que esté en la base de datos al ejecutar una función llamada getUserData y luego esto se establece en el estado. Esto funciona.
Luego, en otra operación, cuando se hace clic en el botón LikeButtonStyle, ejecuta la función likeUnlike que primero verifica cuál es el estado, luego lo establece en el opuesto y luego lo escribe en la base de datos. Ambos funcionan de forma independiente, pero cuando se emparejan, lo que sucede es que cambiará el contador al opuesto, y luego volverá inmediatamente a lo que está en la base de datos.
Como solución, traté de agregar una dependencia de matriz vacía en useEffect que llama a getUserData y eso funciona, pero cuando actualizo, todos los Me gusta vuelven a 0 (predeterminado).
Debe agregar una matriz de dependencia vacía a su useEffect . Esto asegura que solo se llame una vez cuando se monte el componente. Si probó esto como dijo y cuando actualiza la página y sus "me gusta" se restablecen, parece que no se guardan correctamente en su base de datos cuando addInfoToDataBase() .
useEffect(() => { getUserData(); }, []); Lo que sucede aquí es que cada vez que actualiza el estado en su función likeUnlike , useEffect se ejecuta nuevamente. Es por eso que muestra lo que hay en su base de datos que no se está actualizando correctamente o hay una condición de carrera y la solicitud GET regresa antes de que se complete su solicitud POST.
Veo algunos problemas en el código. una es que está permitiendo al usuario cambiar el estado y luego está actualizando el mismo estado desde dentro de un efecto que se desencadena por la actualización del estado. se está creando un bucle aquí.
Recomendaría seguir los cambios que pueden ayudar a evitar condiciones de carrera y fomentar el comportamiento predecible de los componentes.
userCollectionRef al pasar el estado inicial a través de. useState para userLikes .likeCount podría derivarse del estado userLikes .useEffect para actualizar solo los datos en la base de datos.