I made a JavaScript particle animation and it works fine on a normal html website. I tried implementing it into my react app using react helmet/useEffect but both didn't work and I don't know what's going on.
Here is my script:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = 'absolute';
canvas.style.width = '100%';
canvas.style.height = '100%';
const container = document.querySelector('.particles');
container.appendChild(canvas);
let particleArray;
class Particle {
constructor(x, y, dirX, dirY, size, color) {
this.x = x;
this.y = y;
this.dirX = dirX;
this.dirY = dirY;
this.size = size;
this.color = color;
this.scale = .1;
this.counter = 0;
}
draw() {
var gradient = ctx.createRadialGradient(this.x, this.y, this.size / 8, this.x, this.y, this.size);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'white');
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
ctx.shadowColor = this.color;
ctx.shadowBlur = 10;
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
if (this.x + this.size > canvas.width || this.x - this.size < 0) {
this.dirX = -this.dirX;
}
if (this.y + this.size > canvas.height || this.y - this.size < 0) {
this.dirY = -this.dirY;
}
this.size += this.scale;
this.counter += .1;
if (this.counter > 3) {
this.scale = -this.scale;
this.counter = 0;
}
this.x += this.dirX;
this.y += this.dirY;
this.draw();
}
}
function init() {
particleArray = [];
for (let i = 0; i < 25; i++) {
let size = Math.random() * 3;
let x = Math.random() * (innerWidth - size * 2);
let y = Math.random() * (innerHeight - size * 2);
let dirX = (Math.random() * .4) - .2;
let dirY = (Math.random() * .4) - .2;
let colors = ['#721240']
let color = colors[Math.floor(Math.random() * colors.length)];
particleArray.push(new Particle(x, y, dirX, dirY, size, color));
}
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particleArray.length; i++) {
particleArray[i].update();
}
}
init();
animate();
window.addEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
And here is how I tried to add it to my react app in App.js:
<div className="particles">
{useScript("./assets/particles.js")}
</div>
useScript is a react function using useEffect:
import { useEffect } from "react";
function useScript(url) {
useEffect(() => {
const script = document.createElement("script");
script.src = url;
script.async = false;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, [url]);
}
export default useScript;
Please help I'm stuck...
Instead of injecting the script, why don't you directly inject the code itself in useEffect
. That's worked for me on multiple occassions
This is my proposed code. console.log()
things like canvas and particleArray at multiple places to get it right
import { useEffect } from "react";
function useScript(url) {
useEffect(() => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = 'absolute';
canvas.style.width = '100%';
canvas.style.height = '100%';
const container = document.querySelector('.particles');
container.appendChild(canvas);
let particleArray;
class Particle {
constructor(x, y, dirX, dirY, size, color) {
this.x = x;
this.y = y;
this.dirX = dirX;
this.dirY = dirY;
this.size = size;
this.color = color;
this.scale = .1;
this.counter = 0;
}
draw() {
var gradient = ctx.createRadialGradient(this.x, this.y, this.size / 8, this.x, this.y, this.size);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'white');
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
ctx.shadowColor = this.color;
ctx.shadowBlur = 10;
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
if (this.x + this.size > canvas.width || this.x - this.size < 0) {
this.dirX = -this.dirX;
}
if (this.y + this.size > canvas.height || this.y - this.size < 0) {
this.dirY = -this.dirY;
}
this.size += this.scale;
this.counter += .1;
if (this.counter > 3) {
this.scale = -this.scale;
this.counter = 0;
}
this.x += this.dirX;
this.y += this.dirY;
this.draw();
}
}
function init() {
particleArray = [];
for (let i = 0; i < 25; i++) {
let size = Math.random() * 3;
let x = Math.random() * (innerWidth - size * 2);
let y = Math.random() * (innerHeight - size * 2);
let dirX = (Math.random() * .4) - .2;
let dirY = (Math.random() * .4) - .2;
let colors = ['#721240']
let color = colors[Math.floor(Math.random() * colors.length)];
particleArray.push(new Particle(x, y, dirX, dirY, size, color));
}
}
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0, 0, innerWidth, innerHeight);
for (let i = 0; i < particleArray.length; i++) {
particleArray[i].update();
}
}
init();
animate();
window.addEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
return ()=>{
window.removeEventListener('resize', () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
init()
})
}
}, [url]);
}
export default useScript;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.