Aimack Posted October 26, 2023 Share Posted October 26, 2023 I've created a custom cursor whose X and Y gets updated on change of mouse. Using React and GSAP. The cursor also changes in size when it is hovered on a specific text. However, the hover state is not consistent and glitches at the time of using it. I'm sharing the codesandbox link where the same problem is replicated. Any and every help is appreciated, thank you. Codesandbox Link: Link Link to comment Share on other sites More sharing options...
Rodrigo Posted October 26, 2023 Share Posted October 26, 2023 Hi, I think you are overcomplicating this by using state on a parent component only to pass that state to a second child component. You should use React Context for that instead of use the props-drilling approach: https://react.dev/learn/managing-state#passing-data-deeply-with-context https://react.dev/reference/react/createContext Also the approach of using state to update the mouse follower position. That is completely unnecessary because there is not really need to re-render the component every time the entire component every time the mouse moves, right? I think the approaches in this thread can provide a better starting point for this: The examples there use GSAP quickTo() method: https://gsap.com/docs/v3/GSAP/gsap.quickTo() I think this is a better approach IMHO: import { useEffect, useLayoutEffect, useRef } from "react"; import Styles from "./cursor.module.css"; import gsap from "gsap"; // eslint-disable-next-line react/prop-types function Cursor({ hover }) { const cursorRef = useRef(null); const ctx1 = useRef(null); const cursorSize = 30; const mouseMovehandler = (e) => { const { clientX, clientY } = e; ctx1.current.mouseMove( clientX - cursorSize / 2, clientY - cursorSize / 2 ); }; useEffect(() => { ctx1.current = gsap.context((self) => { const xTo = gsap.quickTo(cursorRef.current, "x", {duration: 0.6, ease: "power3"}); const yTo = gsap.quickTo(cursorRef.current, "y", {duration: 0.6, ease: "power3"}); self.add("mouseMove", (x, y) => { xTo(x); yTo(y); }); const scaleTween = gsap.to(cursorRef.current, { scale: 2, duration: 0.05, paused: true, }).reverse(); self.add("grow", (value) => scaleTween.reversed(!value)); }); window.addEventListener("mousemove", mouseMovehandler); return () => { ctx1.current.revert(); window.removeEventListener("mousemove", mouseMovehandler); } }, []); useLayoutEffect(() => { ctx1.current && ctx1.current.grow(hover); }, [hover]); return ( <div className={Styles.cursor} ref={cursorRef} ></div> ); } export default Cursor; https://codesandbox.io/p/github/insightofakash/imgonhover/csb-rdqyhn/draft/xenodochial-moon The blend mode doesn't work, unfortunately we don't have the time resources to tackle everything, so I'll leave that to you. Hopefully this helps. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
Aimack Posted November 9, 2023 Author Share Posted November 9, 2023 Hello @Rodrigo, thanks for your answer but this still doesn't solve the problem. The cursor is buggy when hovered on the text. Also, the codesandbox link isn't accessible so I'm not sure if I'm doing something wrong on my end. Thanks. Link to comment Share on other sites More sharing options...
Rodrigo Posted November 9, 2023 Share Posted November 9, 2023 Hi, The demo seems to be public, I can access it on an incognito window on the browser: https://codesandbox.io/p/github/insightofakash/imgonhover/csb-rdqyhn/draft/xenodochial-moon?file=%2Fsrc%2Fcomponents%2Fcursor%2FCursor.jsx%3A1%2C1 Here is the code of the cursor file just in case: import { useEffect, useLayoutEffect, useRef, useState } from "react"; import Styles from "./cursor.module.css"; import gsap from "gsap"; // eslint-disable-next-line react/prop-types function Cursor({ hover }) { const cursorRef = useRef(null); const [mousePosition, mousePositionChange] = useState({ clientX: 0, clientY: 0 }); const cursorSize = "30"; useEffect(() => { window.addEventListener("mousemove", (e) => { mousePositionChange({ clientX: e.clientX, clientY: e.clientY }); }); return () => window.removeEventListener("mousemove"); }, []); useLayoutEffect(() => { let ctx1 = gsap.context(() => { gsap.to(cursorRef.current, { x: mousePosition.clientX - cursorSize / 2, y: mousePosition.clientY - cursorSize / 2, ease: "back.out(1.8)", }); // console.log("Position Update"); return () => ctx1.revert(); }); }, [mousePosition]); useLayoutEffect(() => { let ctx2 = gsap.context(() => { hover ? gsap.to(cursorRef.current, { height: cursorSize * 2, width: cursorSize * 2, duration: 0.05, }) : gsap.to(cursorRef.current, { height: cursorSize, width: cursorSize, duration: 0.05, }); console.log("Size Update"); return () => ctx2.revert(); }); }, [hover]); return ( <div className={Styles.cursor} ref={cursorRef} ></div> ); } export default Cursor; The issue could be the fact that the scale up/down is triggered constantly. Yeah I don't have time to make that work with the blend mode. There must be a way, but the mouse follow logic is far cleaner and simpler. Happy Tweening! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now