React/NextJS useEffect 计时器每纳秒而不是每秒增加硬币

问题描述 投票:0回答:1

我正在使用 React 开发一个挖矿应用程序,其中计时器应该每秒增加用户的硬币。然而,计时器正在以令人难以置信的快速度(每纳秒)而不是每秒添加硬币。

这是我在 useEffect 挂钩中使用的代码:

   const userDocRef = doc(db, 'users', user.id); // Adjust the path to your Firestore collection
   await setDoc(userDocRef, data, { merge: true });
 };

 useEffect(() => {
   const fetchUserState = async () => {
     
     if (user && !user.anotherStart) {
       toggleSpin();
       const userDocRef = doc(db, 'users', user.id);
 
       try {
         const userDoc = await getDoc(userDocRef);
         if (userDoc.exists()) {
           const userData = userDoc.data();
 
           setUser((prevUser) => ({
             ...prevUser,
             ...userData
           }));
 
           const elapsedTime = Math.floor((Date.now() - userData.startTime) / 1000);
           const remainingTime = userData.countdown - elapsedTime;
           // Start countdown if necessary
           if (elapsedTime >= userData.countdown) {
             await updateUserInFirestore({ isSpinning: false });
             setCoins(user.countdown);
             setShowClaimButton(true); // Show claim button if countdown is completed
             setIsSpinning(false);
             setTimer(null);
           } else {
             startCountdown(remainingTime);
           }
         }
       } catch (error) {
         console.error('Error fetching user state:', error);
       }
     }
     
   };
 
   // Perform initial fetch only once when user.isSpinning is true
   if (user && user.isSpinning) {
     fetchUserState();
   }
   
   
 }, [user, startCountdown]);

这是开始倒计时:

 const startCountdown = (initialTime) => {
   let timeLeft = initialTime;
   setTimer(formatTime(timeLeft));
   countdownRef.current = setInterval(() => {
     setCoins((prev) => prev + user.speed); // Increment coins based on user speed
     timeLeft -= 1;
     setProgress(((initialTime - timeLeft) / initialTime) * 100);
     setTimer(formatTime(timeLeft));
 
     if (timeLeft <= 0) {
       clearInterval(countdownRef.current);
       setIsSpinning(false);
       setTimer(null);
       setShowClaimButton(true);
       updateUserInFirestore({ isSpinning: false, coins: coins + user.speed, progress: 100 });
     }
   }, 1000);
 };

对于切换旋转:

    const coinElement = coinRef.current;
    if (coinElement) {
      coinElement.classList.toggle('spin');
    }
    setIsSpinning(!isSpinning);
    setSpinSpeed((prevSpeed) => Math.min(prevSpeed + user.speed, 10)); // Increase speed
  };

请审查和帮助,我已经尝试了很多逻辑,但没有一个有效。我希望每秒增加一次,我已将计时器设置为 1000,我不知道是否是 useEffect 导致它出现这种行为。我添加了clearInterval以避免内存泄漏,但它阻止了计时器实时显示它的滴答声。谢谢!

reactjs firebase next.js react-hooks telegram
1个回答
0
投票

您的代码中存在多个问题,特别是与您使用 useEffect 和 useEffect 的清理函数的方式相关。

import React, { useEffect, useState, useRef } from 'react';
import { doc, getDoc, setDoc } from 'firebase/firestore';
import db from 'path to your firebaseConfig';

const MiningApp = ({ user }) => {
  const [coins, setCoins] = useState(0);
  const [timer, setTimer] = useState(null);
  const [isSpinning, setIsSpinning] = useState(false);
  const [showClaimButton, setShowClaimButton] = useState(false);
  const [progress, setProgress] = useState(0);
  const countdownRef = useRef(null);

  const formatTime = (time) => {
    //NOTE You can formate time here
    return time;
  };

  const updateUserInFirestore = async (data) => {
    // here you can adjust the path to Firestore collection
    const userDocRef = doc(db, 'users', user.id); 
    await setDoc(userDocRef, data, { merge: true });
  };

  const startCountdown = (initialTime) => {
    let timeLeft = initialTime;
    setTimer(formatTime(timeLeft));
    countdownRef.current = setInterval(() => {
     //NOTE We are Incrementing coins based on  speed of user 
      setCoins((prev) => prev + user.speed); 
      timeLeft -= 1;
      setProgress(((initialTime - timeLeft) / initialTime) * 100);
      setTimer(formatTime(timeLeft));

      if (timeLeft <= 0) {
        clearInterval(countdownRef.current);
        setIsSpinning(false);
        setTimer(null);
        setShowClaimButton(true);
        updateUserInFirestore({ isSpinning: false, coins: coins + user.speed, progress: 100 });
      }
    }, 1000);
  };

  useEffect(() => {
    const fetchUserState = async () => {
      if (user && !user.anotherStart) {
        toggleSpin();
        const userDocRef = doc(db, 'users', user.id);

        try {
          const userDoc = await getDoc(userDocRef);
          if (userDoc.exists()) {
            const userData = userDoc.data();

            setUser((prevUser) => ({
              ...prevUser,
              ...userData
            }));

            const elapsedTime = Math.floor((Date.now() - userData.startTime) / 1000);
            const remainingTime = userData.countdown - elapsedTime;
            // NOTE start countdown if you want 
            if (elapsedTime >= userData.countdown) {
              await updateUserInFirestore({ isSpinning: false });
              setCoins(user.countdown);
              setShowClaimButton(true); // Show claim button if countdown is completed
              setIsSpinning(false);
              setTimer(null);
            } else {
              startCountdown(remainingTime);
            }
          }
        } catch (error) {
          console.error('Error fetching user state:', error);
        }
      }
    };

    //NOTE Performing initial fetch only when user.isSpinning is true once
    if (user && user.isSpinning) {
      fetchUserState();
    }

    return () => {
      if (countdownRef.current) {
        clearInterval(countdownRef.current);
      }
    };
  }, [user]);

  const toggleSpin = () => {
    const coinElement = coinRef.current;
    if (coinElement) {
      coinElement.classList.toggle('spin');
    }
    setIsSpinning(!isSpinning);
//NOTE we are increasing speed here
    setSpinSpeed((prevSpeed) => Math.min(prevSpeed + user.speed, 10)); 
  };

  return (
   //NOTE You can ad your jsx here as it is no need to change it
  );
};

export default MiningApp;
© www.soinside.com 2019 - 2024. All rights reserved.