React组件在屏幕最小化或打开另一个标签时不断重新渲染。

huangapple go评论74阅读模式
英文:

React component keeps re-rendering whenever screen is minimized or another tab is opened

问题

以下是您要翻译的内容:

我在我的投资组合网站中有一个组件,它会每隔几秒钟创建一个对角线移动的圆圈。问题是,当我最小化屏幕或切换选项卡并在一分钟后回来时,会同时创建许多圆圈,并填满屏幕。我不确定为什么会发生这种情况。

您可以在我的网站上实时查看效果:https://khaledalhariri.com

目前我设置最多在屏幕上显示6个圆圈。所以当我最小化窗口并在一分钟后打开它时,会同时创建6个圆圈,这是个问题...如果我没有设置这个6个圆圈的限制,那么将会同时创建无数个圆圈。

代码部分不需要翻译。

英文:

I have a component in my portfolio website that creates a diagonally moving circle every couple of seconds. The problem is that when I minimize the screen or change the tab and come back after a minute, many circles will be created at the same time and the screen gets filled with them. I am not sure why this happens.

You can see the effect live in my website: https://khaledalhariri.com

Currently I have it set to have 6 circles at most in the screen. So when I minimize the window and open it after a minute, 6 circles are created at the same time which is an issue.. if I didnt set that limit of 6 circles then countless circles would have been created at the same time.

Code:

import { useEffect, useRef } from 'react';
import './banner-skills.component.css';
import SKILLS_DATA, { Skill } from '../../data/skills';

const BannerSkills = () => {
  const CREATE_CIRCLE_MS = 4500;
  const CREATE_CIRCLE_MS_MOBILE = 7000;
  const ARRAY_OF_SKILLS: Skill[] = [];
  const isFirstRender = useRef(true);

  useEffect(() => {
    const skillsContainer = document.getElementsByClassName('banner-skills-container')[0];
    let minScreenSize = window.screen.width * 0.08;
    let maxScreenSize = window.screen.width * 0.85;
    let maxCircles = 6;
    let prevInitPos = Math.floor(Math.random() * maxScreenSize) - minScreenSize;

    const createDiagonalCircle = () => {
      if(window.screen.width <= 500) {
        minScreenSize = window.screen.width * 0.8;
        maxCircles = 4;
      }
      else {
        minScreenSize = window.screen.width * 0.08;
        maxCircles = 6;
      }

      if(ARRAY_OF_SKILLS.length >= maxCircles) {
        return;
      }
      
      const circle = document.createElement('div');
      circle.classList.add('skill-circle');
      skillsContainer.appendChild(circle);
      const logo = document.createElement('img');
      let randomSkill = SKILLS_DATA[Math.floor(Math.random() * SKILLS_DATA.length)];
      
      while(ARRAY_OF_SKILLS.indexOf(randomSkill) >= 0) {
        randomSkill = SKILLS_DATA[Math.floor(Math.random() * SKILLS_DATA.length)];
      }

      logo.src = randomSkill.img;
      ARRAY_OF_SKILLS.push(randomSkill);
      circle.appendChild(logo);

      let size = Math.floor(Math.random() * 70) + 70;
      circle.style.width = size + 'px';
      circle.style.height = size + 'px';

      let posTop = -150;
      let posLeft = Math.floor(Math.random() * maxScreenSize) - minScreenSize;

      while(Math.abs(posLeft - prevInitPos) < (window.screen.width * 0.13)) {
        posLeft = Math.floor(Math.random() * maxScreenSize) - minScreenSize;
      }
      
      prevInitPos = posLeft;
      let moveCirclesInterval = setInterval(frame, size - (size * 0.65));
      
      function frame() {
        if (posTop === 500) {
          skillsContainer.removeChild(circle);
          ARRAY_OF_SKILLS.splice(ARRAY_OF_SKILLS.indexOf(randomSkill), 1);
          clearInterval(moveCirclesInterval);
        } else {
          posTop++;
          posLeft++;
          circle.style.top = posTop + 'px';
          circle.style.left = posLeft + 'px';
          circle.style.visibility = 'visible';
        }
      }
      isFirstRender.current = false;
    }

    if(isFirstRender.current === true) {
      createDiagonalCircle();
      if(window.screen.width <= 500) {
        let spawnCirclesInterval = setInterval(createDiagonalCircle, CREATE_CIRCLE_MS_MOBILE);
        return () => clearInterval(spawnCirclesInterval); 
      }
      else {
        let spawnCirclesInterval = setInterval(createDiagonalCircle, CREATE_CIRCLE_MS);
        return () => clearInterval(spawnCirclesInterval); 
      } 
    }
  }, [])

  return (
    <div className="banner-skills-container"></div>
  )
}

export default BannerSkills

The circles are created in the useEffect and I have tried to find out if the page is being re-redenderd or not to stop it but I didn't find anything to work.

答案1

得分: 1

你没有在用户切换标签页或最小化屏幕时清除setInterval函数的时间间隔。createDiagonalCircle 在后台继续运行,即使用户没有主动查看页面,也会创建圆圈。

要解决这个问题,你可以使用window.blurwindow.focus事件来分别停止和重新启动时间间隔。以下是一个示例实现:

useEffect(() => {
  const skillsContainer = document.getElementsByClassName('banner-skills-container')[0];
  let minScreenSize = window.screen.width * 0.08;
  let maxScreenSize = window.screen.width * 0.85;
  let maxCircles = 6;
  let prevInitPos = Math.floor(Math.random() * maxScreenSize) - minScreenSize;
  let intervalId: any;

  const createDiagonalCircle = () => {
    // ... 其余的代码
  };

  const handleVisibilityChange = () => {
    if (document.hidden) {
      clearInterval(intervalId);
    } else {
      intervalId = setInterval(createDiagonalCircle, window.screen.width <= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS);
    }
  };

  if (window.screen.width <= 500) {
    minScreenSize = window.screen.width * 0.8;
    maxCircles = 4;
  } else {
    minScreenSize = window.screen.width * 0.08;
    maxCircles = 6;
  }

  window.addEventListener('blur', () => clearInterval(intervalId));
  window.addEventListener('focus', () => intervalId = setInterval(createDiagonalCircle, window.screen.width <= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS));
  document.addEventListener('visibilitychange', handleVisibilityChange);

  intervalId = setInterval(createDiagonalCircle, window.screen.width <= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS);

  return () => {
    clearInterval(intervalId);
    window.removeEventListener('blur', () => clearInterval(intervalId));
    window.removeEventListener('focus', () => intervalId = setInterval(createDiagonalCircle, window.screen.width <= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS));
    document.removeEventListener('visibilitychange', handleVisibilityChange);
  }
}, [])
英文:

You don't cleare the interval of the setInterval function when the user navigates away from the tab or minimizes the screen. createDiagonalCircle continues to run in the background and creates circles even when the user is not actively viewing the page.

To fix this issue, you can use the window.blur and window.focus events to stop and restart the interval respectively. Here's an example implementation:

useEffect(() =&gt; {
const skillsContainer = document.getElementsByClassName(&#39;banner-skills-container&#39;)[0];
let minScreenSize = window.screen.width * 0.08;
let maxScreenSize = window.screen.width * 0.85;
let maxCircles = 6;
let prevInitPos = Math.floor(Math.random() * maxScreenSize) - minScreenSize;
let intervalId: any;
const createDiagonalCircle = () =&gt; {
// ... rest of the code
};
const handleVisibilityChange = () =&gt; {
if (document.hidden) {
clearInterval(intervalId);
} else {
intervalId = setInterval(createDiagonalCircle, window.screen.width &lt;= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS);
}
};
if (window.screen.width &lt;= 500) {
minScreenSize = window.screen.width * 0.8;
maxCircles = 4;
} else {
minScreenSize = window.screen.width * 0.08;
maxCircles = 6;
}
window.addEventListener(&#39;blur&#39;, () =&gt; clearInterval(intervalId));
window.addEventListener(&#39;focus&#39;, () =&gt; intervalId = setInterval(createDiagonalCircle, window.screen.width &lt;= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS));
document.addEventListener(&#39;visibilitychange&#39;, handleVisibilityChange);
intervalId = setInterval(createDiagonalCircle, window.screen.width &lt;= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS);
return () =&gt; {
clearInterval(intervalId);
window.removeEventListener(&#39;blur&#39;, () =&gt; clearInterval(intervalId));
window.removeEventListener(&#39;focus&#39;, () =&gt; intervalId = setInterval(createDiagonalCircle, window.screen.width &lt;= 500 ? CREATE_CIRCLE_MS_MOBILE : CREATE_CIRCLE_MS));
document.removeEventListener(&#39;visibilitychange&#39;, handleVisibilityChange);
}
}, [])

huangapple
  • 本文由 发表于 2023年4月17日 22:07:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76036056.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定