上下文中的 React 状态变量未按预期更新

问题描述 投票:0回答:1

我正在构建一个具有滑动图像库的组件。基本想法是我有一堆图像,带有

index=== stateIndex
的图像将应用一个活动类。每张图片都会显示一段时间,然后
stateIndex
就会更新。

但是,我无法让上下文状态相应更新。我正在使用功能状态更新,因此状态不应滞后。我以前从未使用过

setInterval
函数,所以不确定这是否是问题所在,或者我是否只是在某个地方遇到了一个简单的错误。

https://playcode.io/1930484

在上面的示例中,单击播放按钮应该会导致图像框以不同的时间间隔在索引 0-4 之间循环。

我有从上下文导入以下对象。

  const [videoOptions, setVideoOptions] = useState({
    currentIndex: null,
    isPlaying: false,
    intervalId: null,
    startTime: 0,
    elapsedTime: 0,
    segmentDurations: [2, 3, 6, 13],
    imgPaths: ["1", "2", "3", "4"],
  });

我的组件有一个简单的框和播放按钮:

    <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>

这些功能相当简单,我只需要适当更新我的状态值即可。

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

控制台日志表明

videoOptions.currentIndex
始终为空。

javascript reactjs
1个回答
0
投票

卸载时的清理间隔:

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

设置初始currentIndex:

setVideoOptions((prev) => ({
  ...prev,
  currentIndex: 0,
  isPlaying: true,
}));

更新 goToNextImage 函数:

setVideoOptions((prev) => {
  const nextIndex = getNextIndex(prev.currentIndex, prev.imgPaths.length);
  console.log("running", nextIndex);

  // Clear previous interval
  clearInterval(intervalId);

  const newIntervalId = setInterval(() => {
    goToNextImage();
  }, prev.segmentDurations[nextIndex] * 1000);

  setIntervalId(newIntervalId);

  return {
    ...prev,
    currentIndex: nextIndex,
    elapsedTime: 0,
  };
});

间隔管理:

const newIntervalId = setInterval(() => {
  goToNextImage();
}, prev.segmentDurations[nextIndex] * 1000);

setIntervalId(newIntervalId);

我确保正确处理滑动图库的状态更新和间隔管理。第一步是添加一个 useEffect 挂钩,该挂钩在组件卸载或 IntervalId 更改时清理间隔,从而防止潜在的内存泄漏。然后,我修改了 startSlideshow 函数,将 currentIndex 初始化为 0,并在开始幻灯片放映时将 isPlaying 设置为 true。这可以确保第一张图像正确显示。我还调整了 goToNextImage 函数以使用 setVideoOptions 中的功能更新,确保状态根据之前的状态正确更新。这有助于捕获间隔回调内的最新状态。此外,我通过清除之前的间隔并在 goToNextImage 中设置新的间隔来管理间隔,确保幻灯片以每个图像片段的正确时间继续播放。这些更改共同确保状态正确更新,并且幻灯片以指定的时间间隔循环显示图像,从而提供预期的功能

© www.soinside.com 2019 - 2024. All rights reserved.