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!

thank you, it is working.

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