Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

284
Views
How to increment a state variable every second in React

I have a list of images in my code for this component called "url". I also have a state variable called currImageIndex. What I want to happen is every time this component is rendered, I would like to start a timer. Every second this timer runs, I would like to increment my state variable currImageIndex. When currImageIndex + 1 is greater than or equal to url length, I would like to reset currImageIndex to zero. The overall goal is to simulate an automatic slideshow of images by just returning <img src={url[currImageIndex]}>. However, I am having issues with incrementing my state variable. I followed some code I found on here, but I can't figure out how to get the increment working. Here is my code.

const { url } = props;
  const [currImageIndex, setCurrImageIndex] = useState(0);
  console.log(url)
  const increment = () => {
    console.log(url.length)
    console.log(currImageIndex)
    if (currImageIndex + 1 < url.length) {
      setCurrImageIndex((oldCount) => oldCount + 1)
    }
    else {
      setCurrImageIndex(0)
    }
  }
  useEffect(() => {
    const id = setInterval(increment, 1000);

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

  return (
    <div className={styles.container}>
      <div className={styles.header}>Preview of GIF:</div>
      <img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
      <div>{currImageIndex}</div>
    </div>
  );

When I run this with a url of size 2, the third to last line ("{currImageIndex}") displays the 1 then 2 then 3 and so on. It does not reset ever. My console.log(url.length) prints 2 and my console.log(currImageIndex) prints 0. What I want to happen is currImageIndex should be 0, 1, 0, 1, 0, 1,.... Can anyone help me understand what I am doing wrong? Thank you!

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

The reason is that the callback passed on setInterval only access the currImageIndex variable in the first render, not the new value while render so you will always get currImageIndex = 0 and pass the condition if (currImageIndex + 1 < url.length). I update your code and make it work like your expectation: https://stackblitz.com/edit/react-y6fqwt

about 4 years ago · Juan Pablo Isaza Report

0

Issue

The issue here is you've a stale enclosure of the currImageIndex state value from the initial render when the increment callback was setup in the interval timer. You're correctly using a functional state to increment the currImageIndex value, but the currImageIndex value in the increment function body is and always will be that of the initial state value, 0.

Solution

A common solution here would be to use a React ref to cache the currImageIndex state so the current value can be accessed in callbacks.

Example:

const [currImageIndex, setCurrImageIndex] = useState(0);
const currentImageIndexRef = useRef();

useEffect(() => {
  // cache the current state value
  currentImageIndexRef.current = currentImageIndex;
}, [currImageIndex]);

const increment = () => {
  // access the current state value
  if (currentImageIndexRef.current + 1 < url.length) {
    setCurrImageIndex((oldCount) => oldCount + 1)
  }
  else {
    setCurrImageIndex(0)
  }
}

useEffect(() => {
  const id = setInterval(increment, 1000);
  return () => clearInterval(id);
}, []);

A simpler solution is to just access the url value that is closed over in component scope with the state updater callback. Use a ternary operator to check if adding 1 to the current value is still less than the url length and state + 1, otherwise reset by returning 0. Note however that if the url array is dynamic and the length changes this solution breaks for the same reason, the url value from the initial render is closed over in scope.

const increment = () => {
  setCurrImageIndex((count) => count + 1 < url.length ? count + 1 : 0);
}

And IMO the simplest solution is to just increment the currImageIndex state always and take the modulus of the url length to always compute a valid, in-range index value. If the url array changes, it doesn't matter as the modulus function will always compute a valid index.

const { url } = props;
const [index, setIndex] = useState(0);
const increment = () => setIndex(i => i + 1);

useEffect(() => {
  const id = setInterval(increment, 1000);
  return () => clearInterval(id);
}, []);

const currImageIndex = index % url.length;

return (
  <div className={styles.container}>
    <div className={styles.header}>Preview of GIF:</div>
    <img src={url[currImageIndex]} alt="GIF Preview" className={styles.image} />
    <div>{currImageIndex}</div>
  </div>
);

Edit how-to-increment-a-state-variable-every-second-in-react

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!