React组件与p5.js画布重复

5

我正在尝试创建一个包含单个p5.js草图的React应用程序。但是,包含p5草图的组件在我的页面上被复制了。不确定为什么会呈现成这种方式。

这里您可以看到代码:https://stackblitz.com/edit/react-ts-kocwqw?file=App.tsx,Sketch.tsx,index.tsx

输入图像描述

以下是React组件的定义:

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>
);

我可能在这里漏掉了什么?


当Sketch组件第一次加载时,它会创建一个画布。然后它被卸载并再次装载。这样,p函数就会运行两次。您应该在useEffect调用中返回一个清理函数来清除创建的画布。 - madzong
2个回答

6
解决方案是从 index.tsx 中删除 <StrictMode>
根据文档,严格模式不能自动检测副作用,但它可以通过使副作用更加确定性来帮助您发现它们。这是通过有意地双重调用来完成的...
看起来严格模式是检测副作用的保障。

这对我来说没有解决问题,还在寻找另一种方法,有什么想法吗? - Ricardo Sanchez

2
另一种在不移除严格模式的情况下找到的解决方案可以在这里找到。

https://www.lloydatkinson.net/posts/2022/how-to-prevent-a-duplicated-canvas-when-using-p5-and-react-strict-mode/

基本上,使用useEffect清理方法,当前的p5实例将被删除,并在下一次热重载时创建一个新的实例。
以下是一个可行的示例:
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;

这是真正的解决方法,而不是被接受的答案。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接