.app {
padding: 10px;
}
.circle {
position: fixed;
transform: translate(-50%, -50%);
top: 0;
left: 0;
opacity: 0.6;
}
.circle.sm {
width: 30px;
height: 30px;
}
.circle.md {
width: 60px;
height: 60px;
}
.circle.lg {
width: 90px;
height: 90px;
}
console.clear();
const { useEffect, useRef, useState, useImperativeHandle, forwardRef } = React;
const Circle = forwardRef(({ size, delay }, ref) => {
const el = useRef();
useImperativeHandle(ref, () => {
return {
moveTo(x, y) {
gsap.to(el.current, { x, y, delay });
}
};
}, [delay]);
return <div className={`circle ${size} gradient-blue`} ref={el}></div>;
});
function App() {
const circleRefs = useRef([]);
circleRefs.current = [];
useEffect(() => {
const { innerWidth, innerHeight } = window;
circleRefs.current.forEach(ref => ref.moveTo(innerWidth / 2, innerHeight / 2));
const onMove = ({ clientX, clientY }) => {
circleRefs.current.forEach(ref => ref.moveTo(clientX, clientY));
};
window.addEventListener("pointermove", onMove);
return () => window.removeEventListener("pointermove", onMove);
}, []);
const addCircleRef = ref => {
if (ref) {
circleRefs.current.push(ref);
}
};
return (
<div className="app">
<p>Move your mouse around</p>
<Circle size="sm" ref={addCircleRef} delay={0} />
<Circle size="md" ref={addCircleRef} delay={0.1} />
<Circle size="lg" ref={addCircleRef} delay={0.2} />
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
View Compiled