I'm trying to create a React app with a single p5.js sketch. However, the ponent containing the p5 sketch is being duplicated on my page. Not sure why it would be rendered this way.
Here you can see the code: .tsx,Sketch.tsx,index.tsx
Here are the react ponents definition:
App.tsx
import React = require('react');
import Sketch from './Sketch';
function App() {
return (
<div className="App">
<Sketch />
</div>
);
}
export default App;
Sketch.tsx
import React = require('react');
import { useEffect } from 'react';
import p5 from 'p5';
const Sketch = () => {
const p = (p5: any) => {
let radius: number;
p5.setup = () => {
p5.createCanvas(p5.windowWidth / 2, p5.windowHeight / 2);
p5.background(0);
radius = 0;
};
p5.draw = () => {
p5.ellipse(p5.width / 2, p5.height / 2, radius, radius);
if (radius < 70) radius++;
};
};
useEffect(() => {
new p5(p);
}, []);
return <></>;
};
export default Sketch;
index.tsx
import * as React from 'react';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
What could I be missing here?
I'm trying to create a React app with a single p5.js sketch. However, the ponent containing the p5 sketch is being duplicated on my page. Not sure why it would be rendered this way.
Here you can see the code: https://stackblitz./edit/react-ts-kocwqw?file=App.tsx,Sketch.tsx,index.tsx
Here are the react ponents definition:
App.tsx
import React = require('react');
import Sketch from './Sketch';
function App() {
return (
<div className="App">
<Sketch />
</div>
);
}
export default App;
Sketch.tsx
import React = require('react');
import { useEffect } from 'react';
import p5 from 'p5';
const Sketch = () => {
const p = (p5: any) => {
let radius: number;
p5.setup = () => {
p5.createCanvas(p5.windowWidth / 2, p5.windowHeight / 2);
p5.background(0);
radius = 0;
};
p5.draw = () => {
p5.ellipse(p5.width / 2, p5.height / 2, radius, radius);
if (radius < 70) radius++;
};
};
useEffect(() => {
new p5(p);
}, []);
return <></>;
};
export default Sketch;
index.tsx
import * as React from 'react';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
What could I be missing here?
Share Improve this question edited May 23, 2022 at 13:32 chris asked May 23, 2022 at 13:27 chrischris 2,8504 gold badges37 silver badges66 bronze badges 1-
When the Sketch ponent is first mounted, it makes one canvas. It then gets unmounted and mounted again. That way, the
p
function is ran twice. You should return a cleanup function in youruseEffect
call to remove the created canvas somehow. – madzong Commented May 23, 2022 at 13:48
2 Answers
Reset to default 6Solution was to remove <StrictMode>
from index.tsx
.
From the docs,
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking...
Looks like Strict Mode is a safeguard to detect side effects.
Another solution without removing the strict mode can be found here
https://www.lloydatkinson/posts/2022/how-to-prevent-a-duplicated-canvas-when-using-p5-and-react-strict-mode/
Basically using the useEffect cleanup method the current p5 instance will be deleted and a new one will be created on the next hot reload.
Here is a working example:
import { useEffect, useRef } from "react";
import p5 from "p5";
function App() {
const p5Ref = useRef();
const Sketch = (p) => {
p.setup = () => {
p.createCanvas(500, 400);
};
p.draw = () => {
p.background(200);
p.rect(p.mouseX, p.mouseY, 100, 100);
};
};
useEffect(() => {
const mp5 = new p5(Sketch, p5Ref.current);
return mp5.remove;
}, []);
return <div ref={p5Ref}></div>;
}
export default App;