我正在使用 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以避免内存泄漏,但它阻止了计时器实时显示它的滴答声。谢谢!
您的代码中存在多个问题,特别是与您使用 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;