首页 > 解决方案 > 空投智能合约组件时间不倒计时?

问题描述

我有空投组件,如果在几秒钟后存入一定数量的硬币,我想在其中空投硬币。所以如果存了金额,我想倒计时,然后给用户一些硬币。但是倒计时功能不起作用。组件重新渲染,但时间仅从 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);
  }
};

这也不起作用。

标签: reactjssettimeoutethereum

解决方案


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>
  );
};

推荐阅读