score:1

Accepted answer

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

score:1

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


Related Query

More Query from same tag