空投智能合约组件的时间没有倒数?



我有一个Airdrop组件,如果有一定量的硬币在几秒钟后被存入,我想要空投硬币。因此,如果金额存入,我想倒计时,然后给一些硬币给用户。然而,倒计时功能不起作用。组件呈现,但时间只从20变到19,然后停止。

这个组件只需要2个道具。

<Airdrop
stakingBalance="50000000000000000000"
// this can be ignored. it wont break the app
// decentralBankContract={props.decentralBankContract}
/>

我手动传递了stakingBalance="50000000000000000000"测试组件。这里是组件本身,你可以将组件复制到你的项目中,或者这里是repo的github地址:https://github.com/yilmazbingo/erc20-token

const Airdrop = (props) => {
console.log("props in Airdrop", props);
const [timeState, setTimeState] = useState({ time: {}, seconds: 20 });
const [timer, setTimer] = useState(0);

useEffect(() => {
let timeLeftVar = secondsToTime(timeState.seconds);
console.log("timelfetvar", timeLeftVar);
setTimeState((prevState) => ({ ...prevState, ...timeLeftVar }));
}, []);
const startTimer = () => {
if (timer == 0 && timeState.seconds > 0) {
setTimer(setInterval(countDown, 1000));
console.log("timer state", timer);
}
};
const countDown = () => {
// 1 . countdown one second at a time
let seconds = timeState.seconds - 1;
setTimeState((prevState) => ({
...prevState,
time: secondsToTime(seconds),
seconds: seconds - 1,
}));
// 2. stop counting when we hit zero
if (timeState.seconds == 0) {
clearInterval(timer);
}
};
const secondsToTime = (secs) => {
let hours, minutes, seconds;
hours = Math.floor(secs / (60 * 60));
let divisor_for_minutes = secs % (60 * 60);
minutes = Math.floor(divisor_for_minutes / 60);
let divisor_for_seconds = divisor_for_minutes % 60;
seconds = Math.ceil(divisor_for_seconds);
let obj = {
h: hours,
m: minutes,
s: seconds,
};
return obj;
};
const airdropReleaseTokens = () => {
let stakingB = props.stakingBalance;
if (stakingB >= "50000000000000000000") {
startTimer();
}
};
airdropReleaseTokens();
return (
<div style={{ color: "black" }}>
{timeState.time.m}:{timeState.time.s}
</div>
);
};
export default Airdrop;

组件渲染器,我认为这个问题与countdown()有关。我把它改成了:

const countDown = () => {
setTimeState((prevState) => ({
...prevState,
time: secondsToTime(timeState.seconds),
seconds: prevState.seconds - 1,
}));
// 2. stop counting when we hit zero
if (timeState.seconds == 0) {
clearInterval(timer);
}
};

这个也不行

代码似乎有几个问题。我相信

setTimeState((prevState) => ({ ...prevState, ...timeLeftVar }));的意思是setTimeState((prevState) => ({ ...prevState, time: timeLeftVar }));基于您以后使用该函数。

无论如何,你真正的问题是基于作用域在反应。问题是你调用的函数是在状态有一个特定值时初始化的,之后它们不会更新。

我不知道你怎么能有你之后的确切行为,同时保持一个状态变量timer(作为使用这些状态的函数以循环的方式相互依赖。

但是,如果您不需要timer状态变量,您可以这样做:

const startTimer = () => {
let tmr = setInterval(() => {
setTimeState((prevState) => {
let updatedSeconds = prevState.seconds - 1;
console.log("Called", updatedSeconds);

if (updatedSeconds == 0) {
clearInterval(tmr);
}

return {
...prevState,
time: secondsToTime(updatedSeconds),
seconds: updatedSeconds,
}
});
}, 1000);
};

当您访问调度函数setTimerState中的状态当前状态值时,此操作有效。这样,可以确保始终使用seconds的当前值,而不是始终使用初始值20秒。

const [timeState, setTimeState] = useState({ time: {}, seconds: 20 });

像这样设置状态是一个坏主意。我把秒分成"airdroptime"。这样我就可以将它作为依赖项添加到useEffect()中。

const Airdrop = (props) => {
console.log("props in Airdrop", props);
const [timeState, setTimeState] = useState({ time: {} });
const [airdropTime, setAirdropTime] = useState(10);
const [timer, setTimer] = useState(0);
useEffect(() => {
let timeLeftVar = secondsToTime(airdropTime);
console.log("timelfetvar", timeLeftVar);
setTimeState((prevState) => ({ ...prevState, time: timeLeftVar }));
if (airdropTime === 0) {
console.log("airdrip time iszero");
clearInterval(timer);
}
}, [airdropTime]);
// this will start the timer
const airdropReleaseTokens = () => {
let stakingB = props.stakingBalance;
if (stakingB >= "50000000000000000000") {
startTimer();
}
};
// each secon state count down will be called and state will be updated
const startTimer = () => {
if (timer === 0 && airdropTime > 0) {
setTimer(setInterval(countDown, 1000));
}
};
const countDown = () => {
setTimeState((prevState) => ({
...prevState,
time: secondsToTime(airdropTime),
}));
setAirdropTime((prevState) => prevState - 1);
};
const secondsToTime = (secs) => {
let hours, minutes, seconds;
hours = Math.floor(secs / (60 * 60));
let divisor_for_minutes = secs % (60 * 60);
minutes = Math.floor(divisor_for_minutes / 60);
let divisor_for_seconds = divisor_for_minutes % 60;
seconds = Math.ceil(divisor_for_seconds);
let obj = {
h: hours,
m: minutes,
s: seconds,
};
return obj;
};
airdropReleaseTokens();
return (
<div style={{ color: "black" }}>
{timeState.time.m}:{timeState.time.s}
</div>
);
};

最新更新