I am building out a component which features a sliding image gallery. The basic idea is I have a bunch of images and the image with index=== stateIndex
will have an active class applied. Each image will be displayed for a period of time and then the stateIndex
will update.
However, I am stuck getting my context state to update accordingly. I am using functional state updates so state shouldn’t be lagging. I have never used the setInterval
function before so not sure if that is the issue or if I just have a simple bug somewhere.
https://playcode.io/1930484
In the above example clicking the play button should cause the image box to cycle through the indexes 0-4 on different intervals.
I have the following object being imported from context.
const [videoOptions, setVideoOptions] = useState({
currentIndex: null,
isPlaying: false,
intervalId: null,
startTime: 0,
elapsedTime: 0,
segmentDurations: [2, 3, 6, 13],
imgPaths: ["1", "2", "3", "4"],
});
and my component features a simple box and play button:
<div className='App'>
<h1>Hello React.</h1>
<div className="image-container">
{videoOptions.imgPaths.map((path, index) => {
return (
<div
key={index}
src={path}
className={`panning-image ${videoOptions.currentIndex === index ? "active" : ""}`}
>{index}</div>
);
})}
</div>
<button
id="play-button"
className="icon-button"
onClick={handlePlayClick}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
</button>
</div>
The functions are fairly straight forward, I just need to get my state values updating appropriately.
const { setVideoOptions, videoOptions } =
useContext(AppContext);
const [intervalId, setIntervalId]= useState(null)
function handlePlayClick() {
if (!videoOptions.isPlaying) {
startSlideshow();
}
}
function startSlideshow(
) {
const images = document.querySelectorAll(".panning-image");
if (images.length > 0) {
console.log('click')
setVideoOptions((prev) => ({
...prev,
currentIndex: 0,
isPlaying: true,
}));
console.log(videoOptions);
// Calculate remaining duration for the current segment
let remainingDuration =
videoOptions.segmentDurations[videoOptions.currentIndex || 0] -
videoOptions.elapsedTime;
console.log(videoOptions);
const newIntervalId = setInterval(() => {
goToNextImage();
}, remainingDuration * 1000);
setIntervalId(newIntervalId)
}
}
function goToNextImage() {
const nextIndex = getNextIndex(
videoOptions.currentIndex,
videoOptions.imgPaths.length
);
console.log("running", nextIndex);
clearInterval(intervalId);
setVideoOptions((prev) => ({
...prev,
currentIndex: nextIndex,
elapsedTime: 0,
}));
}
The console logs indicate that videoOptions.currentIndex
is null at all times.