I am working on a portfolio website using React and I have diagonal moving circles animation showcasing different skills in each circle in the banner of the website. I am using the useEffect hook to create these circles and I have one immediately created when the website opens and then new ones are created every 5 seconds. However, the useEffect keeps re-rendering and many circles are created when I leave the website or minimize it or open another applicaiton. The website sometimes even crashes from the re-rendering.
Website link to see it: https://main--zingy-tiramisu-68c637.netlify.app/
Here is the component I am using for creating and displaying the skill circles:
import React, { useState, useEffect } from 'react';
import './banner-skills.component.css';
import SKILLS_DATA, { Skill } from '../../data/skills';
const BannerSkills = () => {
const CREATE_CIRCLE_MS = 5000;
const ARRAY_OF_SKILLS: Skill[] = [];
useEffect(() => {
const skillsContainer = document.getElementsByClassName('banner-skills-container')[0];
let prevInitPos = Math.floor(Math.random() * 1650) - 150;
const createDiagonalCircle = (): void => {
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() * (window.screen.width * 0.85)) - (window.screen.width * 0.08);
while(Math.abs(posLeft - prevInitPos) < (window.screen.width * 0.13)) {
posLeft = Math.floor(Math.random() * (window.screen.width * 0.85)) - (window.screen.width * 0.08);
}
prevInitPos = posLeft;
let moveCirclesInterval = setInterval(frame, size - (size * 0.65));
function frame() {
if (posTop === 600) {
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';
}
}
}
createDiagonalCircle();
const spawnCirclesInterval = setInterval(createDiagonalCircle, CREATE_CIRCLE_MS);
return () => clearInterval(spawnCirclesInterval);
}, [])
return (
<div className="banner-skills-container"></div>
)
}
export default BannerSkills
I am creating the circles and animating them using JS to move diagonally. I call the function once at the start so a circle appears immediately when the website opens and then the function is called every 5 seconds. Any help is appreciated.
I have tried to create a boolean variable outside of the component as a condition to check if the useEffect is re-rendering or not but it did not work.
I have fixed this issue just now. All I needed to do is add a condition at the beginning of the createDiagonalCircle function in which if there are more than a certain number of circles present (used the array of skills for that) then it will return and stop the function. In my case, I put it to 7. as follows:
const createDiagonalCircle = () => {
if(ARRAY_OF_SKILLS.length >= 7) {
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() * (window.screen.width * 0.85)) - (window.screen.width * 0.08);
while(Math.abs(posLeft - prevInitPos) < (window.screen.width * 0.13)) {
posLeft = Math.floor(Math.random() * (window.screen.width * 0.85)) - (window.screen.width * 0.08);
}
prevInitPos = posLeft;
let moveCirclesInterval = setInterval(frame, size - (size * 0.65));
function frame() {
if (posTop === 600) {
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';
}
}
}