gpt4 book ai didi

javascript - 为什么更改状态 (useState) 会破坏我的 p5.js 代码? ( react + p5.js 应用程序)

转载 作者:行者123 更新时间:2023-12-05 00:38:52 28 4
gpt4 key购买 nike

我使用 p5.js 和 React 创建了一个音频可视化器,我需要一些帮助。
我正在尝试从 Play 更改按钮输入文本的状态至Stop当歌曲开始播放时,来自 Stop返回 Play当用户决定在那一刻停止歌曲时。
我正在使用 react-p5图书馆,一切都很好,直到我 setState当用户点击播放按钮时。由于这会导致重新渲染,它会破坏我的 Canvas 。
有没有办法只重新渲染按钮元素?我不太确定如何在不更改状态的情况下更改按钮的内部文本?

import React, { useState } from 'react';
import Sketch from 'react-p5';
import 'p5/lib/addons/p5.sound';
import Beat from '../../instrumental.mp3';

const App = () => {

let width = 900;
let height = 600;
let song;
let fft;

const [flag, setFlag] = useState(true);

const preload = (p) => {
p.soundFormats('mp3');
song = p.loadSound(Beat);
}

const setup = (p, canvasParentRef) => {
// react-p5 conveniently initializes window.p5 thats why all the other p5's
// have been changed to p in order to create an FFT object
fft = new p5.FFT();
// console.log(p.point)
// use parent to render the canvas in this ref
// without it p5 will render the canvas outside of this component
const canvas = p.createCanvas(width, height).parent(canvasParentRef);
}

const playStop = () => {
if (song.isPlaying()) {
song.pause();
setFlag(true);
//p.noLoop();
} else {
song.play();
setFlag(false);
//p.loop();
}
}

const draw = p => {
p.background(0);
// by default the stroke color is black
// we need to change this in order to see the wave
p.stroke(255, 204, 0);

// no fill in between waves
p.noFill();
// returns an array with 1024 elements
let wave = fft.waveform();

p.beginShape();
// By looping through the waveform data, we are able
// to draw the waveform across the canvas
for (let i = 0; i < width; i++) {
// create an index that maps the for loop variable
// to the index of the wave we want
// value must be integer thats we we use floor
let index = p.floor(p.map(i, 0, width, 0, wave.length));

let x = i;
let y = wave[index] * 100 + height / 2;
p.vertex(x, y);
}
p.endShape();
}

return (
<div className='outerbox'>
<h1>Audio Visualizer</h1>
<Sketch preload={preload} setup={setup} draw={draw}/>
{flag ? <button onClick={playStop}>Play</button> : <button onClick={playStop}>Stop</button>}
</div>
);
}

export default App;
可悲的是没有很多可用的资源,包括 react + p5.js
如果有人想花时间克隆这个存储库以查看问题可能是什么,我将非常感激。
repo 链接: https://github.com/imperium11/audio-visualizer
  • npm i
  • npm run dev-build
  • npm start
  • 最佳答案

    这里的问题是,每次更新功能组件中的状态时,都会再次调用该函数。因此,每次状态更改时,您都重新声明您的 preload/setup/draw , 因为方式react-p5工作,正在运行的草图将开始使用您更新的 draw功能。但是,更新后的绘图函数需要 fft有待定义,但 fft 的版本新的 draw 引用的变量功能未定义。
    为了解决这个问题,您可以将草图使用的任何局部变量变成状态变量。在本例中,我将所有本地人打包到一个对象中:

    const { useState } = React;
    const Sketch = reactP5;

    let v = 0;

    const App = () => {
    const width = 500;
    const height = 300;

    const [flag, setFlag] = useState(true);
    const [locals, setLocals] = useState({});

    const preload = (p) => {
    p.soundFormats('mp3');
    setLocals({
    song: p.loadSound('https://www.paulwheeler.us/files/Ipu.wav')
    });
    }

    const setup = (p, canvasParentRef) => {
    // react-p5 conveniently initializes window.p5 thats why all the other p5's
    // have been changed to p in order to create an FFT object
    setLocals({
    ...locals,
    fft: new p5.FFT()
    });
    // console.log(p.point)
    // use parent to render the canvas in this ref
    // without it p5 will render the canvas outside of this component
    p.createCanvas(width, height).parent(canvasParentRef);
    };

    setup.version = v++;

    const playStop = () => {
    if (locals.song.isPlaying()) {
    locals.song.pause();
    setFlag(true);
    //p.noLoop();
    } else {
    locals.song.play();
    setFlag(false);
    //p.loop();
    }
    }

    const draw = p => {
    p.background(0);
    p.text(setup.version.toString(), 20, 20);
    // by default the stroke color is black
    // we need to change this in order to see the wave
    p.stroke(255, 204, 0);

    // no fill in between waves
    p.noFill();
    // returns an array with 1024 elements
    let wave = locals.fft.waveform();

    p.beginShape();
    // By looping through the waveform data, we are able
    // to draw the waveform across the canvas
    for (let i = 0; i < width; i++) {
    // create an index that maps the for loop variable
    // to the index of the wave we want
    // value must be integer thats we we use floor
    let index = p.floor(p.map(i, 0, width, 0, wave.length));

    let x = i;
    let y = wave[index] * 100 + height / 2;
    p.vertex(x, y);
    }
    p.endShape();
    }

    return (
    <div className='outerbox'>
    <span>Audio Visualizer</span>
    {flag ? <button onClick={playStop}>Play</button> : <button onClick={playStop}>Stop</button>}
    <Sketch preload={preload} setup={setup} draw={draw}/>
    </div>
    );
    }

    ReactDOM.render(
    <React.StrictMode>
    <App />
    </React.StrictMode>,
    document.getElementById('root')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-p5@1.3.27/build/index.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>

    <div id="root"></div>

    另一种方法是将使用这些局部变量的函数实际制作为状态变量。这样,它们只会在第一次为它的每个实例调用组件函数时被声明。这可能有点小技巧,但它的优点是可以快速更新局部变量(如果您在 draw() 函数中更改局部变量,我的理解是您不希望将它们变成状态变量,因为高频状态更新可能会影响性能。

    const { useState } = React;
    const Sketch = reactP5;

    const App = () => {
    const width = 500;
    const height = 300;
    let song;
    let fft;

    const [flag, setFlag] = useState(true);

    const [sketchFns] = useState({
    preload: (p) => {
    p.soundFormats('mp3');
    song = p.loadSound('https://www.paulwheeler.us/files/Ipu.wav');
    },
    setup: (p, canvasParentRef) => {
    // react-p5 conveniently initializes window.p5 thats why all the other p5's
    // have been changed to p in order to create an FFT object
    fft = new p5.FFT();
    // console.log(p.point)
    // use parent to render the canvas in this ref
    // without it p5 will render the canvas outside of this component
    p.createCanvas(width, height).parent(canvasParentRef);
    },
    playStop: () => {
    if (song.isPlaying()) {
    song.pause();
    setFlag(true);
    //p.noLoop();
    } else {
    song.play();
    setFlag(false);
    //p.loop();
    }
    },
    draw: p => {
    p.background(0);
    // by default the stroke color is black
    // we need to change this in order to see the wave
    p.stroke(255, 204, 0);

    // no fill in between waves
    p.noFill();
    // returns an array with 1024 elements
    let wave = fft.waveform();

    p.beginShape();
    // By looping through the waveform data, we are able
    // to draw the waveform across the canvas
    for (let i = 0; i < width; i++) {
    // create an index that maps the for loop variable
    // to the index of the wave we want
    // value must be integer thats we we use floor
    let index = p.floor(p.map(i, 0, width, 0, wave.length));

    let x = i;
    let y = wave[index] * 100 + height / 2;
    p.vertex(x, y);
    }
    p.endShape();
    }
    });

    return (
    <div className='outerbox'>
    <span>Audio Visualizer</span>
    {flag ? <button onClick={sketchFns.playStop}>Play</button> : <button onClick={sketchFns.playStop}>Stop</button>}
    <Sketch preload={sketchFns.preload} setup={sketchFns.setup} draw={sketchFns.draw}/>
    </div>
    );
    }

    ReactDOM.render(
    <React.StrictMode>
    <App />
    </React.StrictMode>,
    document.getElementById('root')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/react-p5@1.3.27/build/index.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>

    <div id="root"></div>

    关于javascript - 为什么更改状态 (useState) 会破坏我的 p5.js 代码? ( react + p5.js 应用程序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71013225/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com