skip to Main Content

I have a progress bar the value should be from 0.1 to 1.

but sometimes progressValue will over 1, for example refresh the page.

Why ?

https://codesandbox.io/p/devbox/g9wwqf?file=%2Fsrc%2FApp.jsx%3A6%2C1

import "./styles.css";
import axios from "axios";
import { useState, useEffect } from "react";

let intervalId;

export default function App() {
  const [progressValue, setProgressValue] = useState(0);

  useEffect(() => {
    intervalId = setInterval(() => {
      if (progressValue < 1) {
        setProgressValue((t) => t + 0.3);
      }
    }, 100);

    return () => clearInterval(intervalId);
  }, []);

  useEffect(() => {
    axios
      .get("https://randomuser.me/api/?results=5")
      .then((value) => {
        // success
        clearInterval(intervalId);
        setProgressValue(1);
      })
      .catch((error) => {
        // error
        clearInterval(intervalId);
        setProgressValue(1);
      });
  }, []);

  console.log("progressValue =>", progressValue);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

2

Answers


  1. Please pass the progressValue dependency correctly to the effect. Otherwise the progressValue will always refer to the value of progressValue from the very first render, which was 0.

    If you log the value of progressValue before the if condition, it will log 0. That’s just how closures work. So anyway doing that condition check will do you no good.

    enter image description here

    Instead you can make use of the condition inside the setState callback correctly like:

      useEffect(() => {
        intervalId = setInterval(() => {
          setProgressValue((t) => {
            if (t + 0.3 <= 1) return t + 0.3;
            else return t;
          });
        }, 100);
    
        return () => clearInterval(intervalId);
      }, []);
    
    

    I am sure you are looking for the sum value to not exceed 1, so the conditions should check for that and not t < 1

    Login or Signup to reply.
  2. You should make your intervalId a part of your App component. A way to achieve this would be to create a reference using useRef.

    I also wrapped the Axios call in a 1 second delay so that the progress effect can actually be seen.

    const { useCallback, useEffect, useRef, useState } = React;
    
    const App = () => {
      const intervalId = useRef(null);
      const [progressValue, setProgressValue] = useState(0);
    
      const cancelInterval = useCallback(() => {
        clearInterval(intervalId.current);
        intervalId.current = null;
      }, [intervalId]);
    
      useEffect(() => {
        intervalId.current = setInterval(() => {
          setProgressValue((currProgressValue) => {
            const nextProgressValue = currProgressValue + 0.3;
            return Math.min(nextProgressValue, 1);
          });
        }, 100);
        return () => cancelInterval();
      }, []);
    
      useEffect(() => {
        // Delay the Axios call for 1 second, so the interval occurs
        setTimeout(() => {
          axios
            .get("https://randomuser.me/api/?results=5")
            .then((value) => {
              console.log('Success');
            })
            .catch((error) => {
              console.log(`Error: ${error}`);
            })
            .finally(() => {
              cancelInterval();
              setProgressValue(1);
            });
        }, 1000);
      }, []);
      
      useEffect(() => {
        console.log("progressValue =>", progressValue);
      }, [progressValue]);
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
        </div>
      );
    };
    
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.8/axios.min.js"></script>
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search