Skip to content

Commit

Permalink
refactor: Optimize ParticlesContainer component to load SVG logos lazily
Browse files Browse the repository at this point in the history
  • Loading branch information
singhAmandeep007 committed Dec 6, 2024
1 parent ba61c5d commit 95033ba
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 49 deletions.
71 changes: 69 additions & 2 deletions src/Components/Particles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import Particles, { initParticlesEngine } from "@tsparticles/react";
import { loadSlim } from "@tsparticles/slim";

import type { Container } from "@tsparticles/engine";

import { particlesOptions } from "./particlesOptions";

import { techLogoNames } from "@/Common/techlogos";

const BATCH_LOAD_INTERVAL = 1000;
// NOTE: this should be 1 to load all logos, needs fix
const BATCH_SIZE = 1;

export const ParticlesContainer = () => {
const [init, setInit] = useState(false);
const [particlesLoaded, setParticlesLoaded] = useState(false);

const particleContainerRef = useRef<Container | null>(null);

const [loadedTechLogos, setLoadedTechLogos] = useState<string[]>([]);

// this should be run only once per application lifetime
useEffect(() => {
Expand All @@ -19,17 +32,71 @@ export const ParticlesContainer = () => {
.catch(console.error);
}, []);

const handleParticlesLoaded = useCallback(async (container?: Container) => {
if (container) {
particleContainerRef.current = container;
setParticlesLoaded(true);
}
return Promise.resolve();
}, []);

useEffect(() => {
if (!particlesLoaded) return;

const interval = setInterval(() => {
const nextIndex = loadedTechLogos.length;
const nextBatch = techLogoNames.slice(nextIndex, nextIndex + BATCH_SIZE);

if (nextBatch.length === 0) {
clearInterval(interval);
return;
}

particleContainerRef.current?.particles.addParticle(undefined, {
number: { density: { enable: true }, value: techLogoNames.length },
opacity: {
value: { min: 0, max: 0.5 },
},
move: {
enable: true,
direction: "none",
outModes: {
default: "out",
},
random: false,
speed: 8,
straight: false,
vibrate: true,
},
size: {
value: 16,
},
// READ-MORE: https://particles.js.org/docs/interfaces/tsParticles_Engine.Options_Interfaces_Particles_Shape_IShape.IShape.html
shape: {
options: {
image: nextBatch.map((logoName) => ({ src: `./logos/${logoName}.svg` })),
},
type: "image",
},
});

setLoadedTechLogos((currentLogos) => [...currentLogos, ...nextBatch]);
}, BATCH_LOAD_INTERVAL); // load a batch of size<BATCH_SIZE> every <BATCH_LOAD_INTERVAL>seconds
return () => clearInterval(interval);
}, [particlesLoaded, loadedTechLogos]);

const particles = useMemo(() => {
if (init) {
return (
<Particles
id="tsparticles"
options={particlesOptions}
particlesLoaded={handleParticlesLoaded}
/>
);
}
return null;
}, [init]);
}, [init, handleParticlesLoaded]);

return <div style={{ width: 0, height: 0 }}>{particles}</div>;
};
Expand Down
47 changes: 0 additions & 47 deletions src/Components/Particles/particlesOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { techLogos } from "@/Common/techlogos";

import type { ISourceOptions } from "@tsparticles/engine";

const particlesOptions: ISourceOptions = {
Expand All @@ -14,53 +12,8 @@ const particlesOptions: ISourceOptions = {
zIndex: -1,
},
fpsLimit: 60,
particles: {
number: {
density: {
enable: true,
},
value: 40,
},
move: {
direction: "none",
enable: true,
outModes: {
default: "out",
},
random: false,
speed: 3,
straight: false,
},
opacity: {
animation: {
enable: true,
speed: 0.5,
sync: false,
delay: 1,
},
value: { min: 0, max: 0.5 },
},
size: {
value: 18,
},
shape: {
// READ-MORE: https://particles.js.org/docs/interfaces/tsParticles_Engine.Options_Interfaces_Particles_Shape_IShape.IShape.html
options: {
image: [],
},
type: "image",
},
},
preload: [],

detectRetina: true,
};

const particleOptionsImage = Object.values(techLogos).map(({ src }) => ({
src,
}));

// @ts-expect-error-next-line
particlesOptions.particles.shape.options.image = particleOptionsImage;

export { particlesOptions };

0 comments on commit 95033ba

Please sign in to comment.