やりたいこと
Reactとp5.jsをいい感じに連携する
Reactのインストール
まず、React+Typescript環境を準備します。
npx create-react-app p5-react --template typescript
cd p5-react
yarn start

これでReactのプロジェクト作成は完了しました!次はp5.jsをインストールしていきます。
p5.jsのインストール
yarn add p5 @types/p5
これでp5.jsのインストールは完了です!次はコンポーネントを作成していきます。
Squareコンポーネントの作成
Square.tsxを作成します。
// src/Square.tsx
import React, { useEffect } from 'react';
import p5 from 'p5';
const sketch = (p: p5) => {
p.setup = () => {
// キャンバスを作成して#squareの子に配置する
p.createCanvas(p.windowWidth / 2, p.windowHeight / 2).parent('square')
}
p.draw = () => {
p.clear()
for (let i = 0; i < 3; i++) {
p.square(10 + (i * 100), 10, 100)
}
}
}
const Square: React.FC = () => {
useEffect(() => {
new p5(sketch)
}, [])
return (
// idをsquareに指定する
<div id="square"/>
);
}
export default Square;
App.tsxでimportします。
// src/App.tsx
import React from 'react';
import './App.css';
import Square from "./Square";
function App() {
return (
<div className="App">
<Square/>
</div>
);
}
export default App;
重要なのがp5のキャンバスを入れたい親要素にidを指定することです!!
親要素にidを指定してcreateCanvas
時に.parent('square')
メソッドを実行しなければ以下のようなHTMLが吐き出されます。
<html>
<head>
:
</head>
<body>
<div id="root">
<div class="App">
<div id="square"></div>
</div>
</div>
:
<main>
<canvas id="defaultCanvas0" class="p5Canvas" width="1920" height="944" style="width: 1920px; height: 944px;"></canvas>
</main>
</body>
</html>
これではSquareコンポーネントと連携しているとは言えないですね。サンプルのコードの通りに書いていると以下のHTMLが吐き出されます。
<html>
<head>
:
</head>
<body>
<div id="root">
<div class="App">
<div id="square">
<canvas id="defaultCanvas0" class="p5Canvas" width="1920" height="944" style="width: 1920px; height: 944px;"></canvas>
</div>
</div>
</div>
:
<main></main>
</body>
</html>
これでブラウザで確認すると、、

四角形が三つ表示されています!p5.jsをReact+Typescriptのコンポーネントで実行することができました!
Stateの連携
StateはReactのコンポーネント内でしか読み取りも書き込みもできないのでp5.jsと連携するにはコンポーネント外で定義した変数でStateを管理してp5.jsとReactコンポーネントを連携します。
// src/Square.tsx
import React, { useEffect, useState } from 'react';
import p5 from 'p5';
// 連携のための四角形の個数を入れる変数を定義だけしておく
let quantityState: number
const sketch = (p: p5) => {
p.setup = () => {
p.createCanvas(p.windowWidth / 2, p.windowHeight / 2).parent('square')
}
p.draw = () => {
p.clear()
// quantityState分四角形を表示させる
for (let i = 0; i < quantityState; i++) {
p.square(10 + (i * 100), 10, 100)
}
}
}
const Square: React.FC = () => {
// React部分でuseStateする
const [quantity, setQuantity] = useState(3)
// 連携のための四角形の個数を入れる変数にStateが変わるたびに代入する
quantityState = quantity
useEffect(() => {
new p5(sketch)
}, [])
return (
<div>
<div id="square"/>
// Stateを変更するボタン
<button onClick={() => setQuantity(quantity - 1)}>減らす</button>
<button onClick={() => setQuantity(quantity + 1)}>増やす</button>
</div>
);
}
export default Square;
これでp5.jsとReactコンポーネントの連携も完了です。ブラウザで確認します。

うまく動いていますね!連携も完了です!
これで解説を終わります。ありがとうございました。
ソースコードはこちらに置いてます。