Recreate canvas with p5 and Reactjs

Hi,

I am trying to implement p5 with react. On the initial render the canvas gets created, however I want to restart the game by clicking a button.
I see that the canvas is there but only it’s frame, it is never properly filled.

Can someone point me in the right direction, how I can recreate the canvas and restart the creation of the p5 object?

I would be grateful for that.

export default function P5() {
  const windowDim = getWindowDimensions()

  const p5Options = ["snake"] 

  const [option, setOption] = React.useState(p5Options[0])
  const [canvasDivKey, setCanvasDivKey] = React.useState("1")

  const p5DivRef = React.useRef()
  const sketchRef = React.useRef()

  function setNewGame(opt) {
    setOption(opt)
    setCanvasDivKey("2")

    if (sketchRef.current) {
      sketchRef.current.remove()

     // doesn't work
      sketchRef.current = new p5(p5Sketch, p5DivRef.current)
    }
  }

  const prevOption = usePrevious(option)
  React.useEffect(() => {
    if (!sketchRef.current || (prevOption && option && prevOption !== option)) {
      if (sketchRef.current) {
        sketchRef.current.remove()
      }
      // doesn't work the 2nd time either
      sketchRef.current = new p5(p5Sketch, p5DivRef.current)
    }

    if (sketchRef.current) return sketchRef.current.remove

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [option])

  function p5Sketch(sketch) {
    const canvasDim = {
      width: windowDim.width > 1100 ? 800 : windowDim.width - 250,
      height: Math.min(500, windowDim.height),
    }

    let extraCanvas

    sketch.setup = () => {
      sketch.createCanvas(canvasDim.width, canvasDim.height).parent(p5DivRef.current)

      extraCanvas = sketch.createGraphics(canvasDim.width, canvasDim.height)
      extraCanvas.clear()
    }

    sketch.draw = () => {
      switch (option) {
        case "snake":
          snake(sketch, {})
          break
        default:
          break
      }
    }

    sketch.windowResized = () => {
      sketch.resizeCanvas(sketch.windowWidth, sketch.windowHeight)
    }
  }

  return (
    <Layout>
      <Radio.Group
        style={{ marginBottom: "1rem" }}
        value={option}
      >
        {p5Options.map((opt) => (
          <Radio.Button
            key={opt}
            value={opt}
            onClick={() => {
              setNewGame(opt)
            }}
          >
            {_capitalize(opt)}
          </Radio.Button>
        ))}
      </Radio.Group>

      <div key={canvasDivKey} ref={p5DivRef} />
    </Layout>
  )
}

On initial render:

On button click it is just an empty <div></div>, with no content.

Hi! welcome to the forum!

I don’t use react but had a similar issue when using another framework called choo.io. I ended up using canvasElement parameter from

canvas = createCanvas(...);
canvasElement = canvas.elt;

and inject canvasElement directly under the div you want.

By the way, this is p5.js and not Processing so it would be great if you can fix the category. Thanks!

2 Likes

thank you, it is working.

Now I just have to implement to reset the state and redraw on the canvas.

1 Like