You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React项目中使用react-script-tag与react-router-dom嵌入p5js草图

问题原因

两个核心问题导致你现在的异常:

  • 路由跳转不加载:React Router是客户端无刷新路由,react-script-tag的加载逻辑没有适配React组件的挂载生命周期,只有整页刷新时浏览器才会主动执行脚本资源,客户端切路由时脚本不会自动触发执行。
  • 跳转后草图残留:p5.js默认全局模式下会把生成的canvas直接追加到页面<body>末尾,不属于你写的.p5js容器的子元素,路由切换时你的页面组件被卸载,但全局挂载的canvas和p5的帧循环、事件监听都不会被自动清理,所以会一直留在页面上。
解决方案

不要用react-script-tag引外部脚本,用p5官方的实例模式配合React生命周期处理加载和卸载,这是React项目集成p5最稳定的方式,步骤如下:

  1. 安装p5依赖
    执行命令安装p5 npm包,比外链脚本更适配单页应用的构建流程:
npm install p5
  1. 修改p5草图为实例模式
    把你原来的sketch2.js从全局写法改成实例模式,导出草图函数,避免污染全局作用域,同时方便后续控制挂载位置和销毁。
    原全局写法参考:
// 原全局模式写法
function setup() {
  createCanvas(400, 400);
}
function draw() {
  background(220);
  // 你的绘制逻辑
}

修改后的实例模式:

// 修改后的sketch2.js
export default function sketch(p) {
  p.setup = function () {
    // 后续会指定canvas挂载到对应容器,不会直接插在body末尾
    p.createCanvas(800, 600);
  }

  p.draw = function () {
    p.background(220);
    // 原有绘制逻辑保留,所有p5内置方法前面加p.前缀即可
  }
}
  1. 重写p5js页面组件
    用useRef保存p5实例和容器引用,useEffect处理组件挂载时的初始化、卸载时的清理逻辑,注意React组件名需要大写开头:
import React, { useEffect, useRef } from 'react';
import p5 from 'p5';
// 引入修改后的实例模式草图,注意路径匹配你本地的文件位置
import sketch from '../sketch2.js';

const P5jsPage = () => {
  const containerRef = useRef(null);
  const p5InsRef = useRef(null);

  useEffect(() => {
    // 组件挂载(即路由跳转到/p5js)时,初始化p5实例,挂载到指定容器
    p5InsRef.current = new p5(sketch, containerRef.current);

    // 组件卸载(即路由切走)时,销毁p5实例,移除canvas、帧循环和事件监听
    return () => {
      p5InsRef.current.remove();
    }
  }, []);

  return <div className="p5js" ref={containerRef}></div>
}

export default P5jsPage;
  1. 修正App.js里的路由引用
    因为组件名改成了大写开头的P5jsPage,对应调整导入和路由配置:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "./App.css";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import SQL from "./pages/SQL";
import SuperCollider from "./pages/SuperCollider";
// 调整导入名
import P5jsPage from "./pages/p5js";

function App() {
  return (
    <>
      <BrowserRouter>
        <Navbar />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/sql" element={<SQL />} />
          <Route path="/sc" element={<SuperCollider />} />
          {/* 调整路由element */}
          <Route path="/p5js" element={<P5jsPage />} />
        </Routes>
      </BrowserRouter>
    </>
  );
};

export default App;

改完后效果:

  • 路由跳转到/p5js时组件自动挂载,p5草图会立即初始化渲染,不需要手动刷新页面
  • 跳转到其他路由时,组件卸载逻辑会自动销毁p5实例、清除canvas,不会有残留
  • 不会污染全局作用域,也不会因为p5的帧循环持续运行导致页面内存泄漏

如果你坚持要保留原有的外链脚本+全局模式写法,需要自己在useEffect里手动创建script标签插入DOM,卸载时手动删除script、查找删除body下p5生成的canvas、清除window上挂载的p5全局方法和requestAnimationFrame循环,这种方式容易遗漏清理逻辑造成内存泄漏,不推荐使用。

内容的提问来源于stack exchange,提问作者spal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 11:33:12