简体   繁体   English

React 和 setTimeout/setInterval 导致渲染问题

[英]React and setTimeout/setInterval causing render issues

I am quite new to React, learning it for 1 year, but I stuck with the simple slideshow component.我对 React 很陌生,学习了 1 年,但我坚持使用简单的幻灯片组件。 I have to display images in a 2 seconds interval, but it causes the background to clip or rather re-render when scrolling.我必须以 2 秒的间隔显示图像,但这会导致背景在滚动时被剪辑或重新渲染。 I have to solve it, which means I must use some sort of autoplay and still not break the page.我必须解决它,这意味着我必须使用某种自动播放并且仍然不会破坏页面。 I attach the code and a GIF that shows my issue and it can be seen that a background-colored row appears above the image slideshow.我附上了显示我的问题的代码和 GIF,可以看到图像幻灯片上方出现了一个背景色的行。 Also when I removed the whole component the page did not produce this rendering issue.此外,当我删除整个组件时,页面也没有产生这个渲染问题。 Please I really need some help regarding this problem, I am hoping somebody who is more experienced with React can tell me how to approach this.关于这个问题,我真的需要一些帮助,我希望对 React 更有经验的人可以告诉我如何解决这个问题。 The slideshow component:幻灯片组件:

import React, { useState, useEffect } from "react";
import { hands } from "../../../../assets/images/landing_hands/index.js";
import { AnimatePresence, motion } from "framer-motion";

const ImageSlideShow = () => {
    const [slideShowInterval, setSlideShowInterval] = useState(null);
    const [activeImage, setActiveImage] = useState(0);

    const DURATION = 2000;
    const killAutoPlay = () => {
        console.log("killing interval");
        clearInterval(slideShowInterval);
        setSlideShowInterval(null);
    };

    const startAutoPlay = () => {
        if (slideShowInterval === null) {
            console.log("starting interval");
            const int = setInterval(() => {
                setActiveImage((prev) => {
                    let nextIndex = prev + 1;

                    if (nextIndex >= hands.length) {
                        return 0;
                    } else return nextIndex;
                });
            }, DURATION);

            setSlideShowInterval(int);
        }
    };

    useEffect(() => {
        document.addEventListener(
            "visibilitychange",
            () => {
                console.log(document.visibilityState);
                if (document.visibilityState === "hidden") {
                    killAutoPlay();
                } else {
                    startAutoPlay();
                }
            },
            false
        );

        return () => {
            document.removeEventListener("visibilitychange", () => {});
        };
    }, []);
    return (
        <AnimatePresence>
            <motion.img
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                exit={{ opacity: 0 }}
                src={hands[activeImage]}
                alt={"nft"}
            />
        </AnimatePresence>
    );
};

export default ImageSlideShow;

GIF: https://lh4.googleusercontent.com/t_dQ7NqHxHfcZJzd-FV00Sg2NaBd5nZ1uaUohFafnL06qyx5bFQRIgPHBHJwZkeQva8=w2400 GIF: https://lh4.googleusercontent.com/t_dQ7NqHxHfcZJzd-FV00Sg2NaBd5nZ1uaUohFafnL06qyx5bFQRIgPHBHJwZkeQva8=w2400

I appreciate all your effort and answers.我感谢您的所有努力和回答。

I updated the code with Sergey Sosunov's approach, still getting the rendering glitch, deplyed the app to Vercel and made the repository public.我用 Sergey Sosunov 的方法更新了代码,仍然出现渲染故障,将应用程序部署到 Vercel 并将存储库公开。 https://vercel.com/zsoltgombocz/cwp-new https://github.com/zsoltgombocz/cwp-new https://vercel.com/zsoltgombocz/cwp-new https://github.com/zsoltgombocz/cwp-new

Also after the new code added to the project, I captured the screen to show how the purple backgroud glitches through the image slideshow.同样在将新代码添加到项目之后,我捕获了屏幕以显示紫色背景如何通过图像幻灯片出现故障。 https://lh6.googleusercontent.com/fhqqH5SOOt-PbM4K03qADwQEJKNg_fXR-IU1iCdbD7gXUx2F5TKKnluo6aUenEQFZnE=w2400 https://lh6.googleusercontent.com/fhqqH5SOOt-PbM4K03qADwQEJKNg_fXR-IU1iCdbD7gXUx2F5TKKnluo6aUenEQFZnE=w2400

I tried to reproduce your issue but the only thing i faced was multiple setTimeouts execution.我试图重现您的问题,但我唯一面临的是多次 setTimeouts 执行。 Your document.removeEventListener is invalid and does not work as expected, also, things should be done much more easier than you did.您的document.removeEventListener无效并且无法按预期工作,而且,事情应该比您做的更容易。

import { useState, useEffect } from "react";
import { hands } from "./hands";
import "./styles.css";
import { AnimatePresence, motion } from "framer-motion";

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

const ImageSlideShow = () => {
  const DURATION = 2000;
  const [isVisible, setIsVisible] = useState(true);
  const [activeImage, setActiveImage] = useState(0);

  useEffect(() => {
    if (!isVisible) return;
    const intervalId = setInterval(() => {
      setActiveImage((prev) => {
        const next = prev + 1;
        return next >= hands.length ? 0 : next;
      });
    }, DURATION);

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

  useEffect(() => {
    const onVisibilityChange = () => {
      console.log(document.visibilityState);
      setIsVisible(document.visibilityState !== "hidden");
    };

    document.addEventListener("visibilitychange", onVisibilityChange);

    return () => {
      document.removeEventListener("visibilitychange", onVisibilityChange);
    };
  }, []);

  return (
    <AnimatePresence>
      <motion.img
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        src={hands[activeImage]}
        alt={"nft"}
      />
    </AnimatePresence>
  );
};

编辑无价的meitner-s7cwmd

Try to change your code to this one and tell if issue still exists.尝试将您的代码更改为此代码并判断问题是否仍然存在。 If yes - i honestly dont know how to help until you provide a way to reproduce it.如果是的话 - 我真的不知道如何提供帮助,直到您提供一种重现它的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM