Search code examples
reactjsuse-effect

Can i call a specific function inside `useEffect` in React?


I have a canvas component in react. I am using useEffect to get the canvas element. So i have defined all needed functions in useEffect, as you can see below

import { useEffect, useRef } from "react"
import * as blobs2Animate from "blobs/v2/animate"

export const CornerExpand = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null)

  useEffect(() => {
    const canvas = canvasRef.current!
    const ctx = canvas.getContext("2d")
    const animation = blobs2Animate.canvasPath()

    const width = canvas.clientWidth * window.devicePixelRatio
    const height = canvas.clientHeight * window.devicePixelRatio
    canvas.width = width
    canvas.height = height

    const renderAnimation = () => {
      if (!ctx) return
      ctx.clearRect(0, 0, width, height)
      ctx.fillStyle = "#E0F2FE"
      ctx.fill(animation.renderFrame())
      requestAnimationFrame(renderAnimation)
    }
    requestAnimationFrame(renderAnimation)

    const size = Math.min(width, height) * 1
    const defaultOptions = () => ({
      blobOptions: {
        seed: Math.random(),
        extraPoints: 36,
        randomness: 0.7,
        size,
      },
      canvasOptions: {
        offsetX: -size / 2.2,
        offsetY: -size / 2.2,
      },
    })

    const loopAnimation = () => {
      animation.transition({
        duration: 4000,
        timingFunction: "ease",
        callback: loopAnimation,
        ...defaultOptions(),
      })
    }

    animation.transition({
      duration: 0,
      callback: loopAnimation,
      ...defaultOptions(),
    })

    const fullscreen = () => {
      const options = defaultOptions()
      options.blobOptions.size = Math.max(width, height) * 1.6
      options.blobOptions.randomness = 1.4
      options.canvasOptions.offsetX = -size / 2
      options.canvasOptions.offsetY = -size / 2
      animation.transition({
        duration: 2000,
        timingFunction: "elasticEnd0",
        ...options,
      })
    }
  }, [canvasRef])

  return (
    <div>
      <canvas className="absolute top-0 left-0 h-full w-full" ref={canvasRef} />
    </div>
  )
}
export default CornerExpand

Everything works as well, but now I have a problem. I want to execute the fullscreen() function when a button is clicked in the parent component. Since I have defined the function in useEffect, I can't call it directly, isn't it? What can I do to solve this?


Solution

  • You can do it like this.

    export const CornerExpand = React.forwardRef((props, ref) => {
    //....
      {
      //...
        const fullscreen = () => {
          const options = defaultOptions()
          options.blobOptions.size = Math.max(width, height) * 1.6
          options.blobOptions.randomness = 1.4
          options.canvasOptions.offsetX = -size / 2
          options.canvasOptions.offsetY = -size / 2
          animation.transition({
            duration: 2000,
            timingFunction: "elasticEnd0",
            ...options,
          })
        }
        ref.current = fullscreen;
      }, [canvasRef]);
    

    You can wrap this comp with React.forwardRef. And call it from parent.

    <CornerExpand ref={fullscreenCallbackRef} />
    

    And then call like this

    fullscreenCallbackRef.current()