簡體   English   中英

"<i>Why does changing state (useState) break my p5.js code?<\/i>為什么更改狀態 (useState) 會破壞我的 p5.js 代碼?<\/b> <i>(React + p5.js application)<\/i> (反應 + p5.js 應用程序)<\/b>"

[英]Why does changing state (useState) break my p5.js code? (React + p5.js application)

我使用 p5.js 和 React 創建了一個音頻可視化器,我需要一些幫助。

我試圖在歌曲開始播放時將按鈕輸入文本的狀態從Play更改為Stop ”,並在用戶決定在那一刻停止歌曲時將“ Stop ”更改為Play ”。

我正在使用react-p5庫,並且在用戶單擊播放按鈕時我setState之前一切正常。 由於這會導致重新渲染,它會破壞我的畫布。

有沒有辦法只重新渲染按鈕元素? 我不太確定如何在不更改狀態的情況下更改按鈕的內部文本?

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

如果有人想花時間克隆這個存儲庫以查看問題可能是什么,我將非常感激。

回購鏈接: https ://github.com/imperium11/audio-visualizer

  1. npm i
  2. npm run dev-build
  3. npm start

這里的問題是,每次更新功能組件中的狀態時,都會再次調用該函數。 結果,每次狀態更改時,您都重新聲明preload<\/code> \/ setup<\/code> \/ draw<\/code> ,由於react-p5<\/code>的工作方式,正在運行的草圖將開始使用您更新的draw<\/code>功能。 但是,更新后的繪圖函數需要定義fft<\/code> ,但新draw<\/code>函數引用的fft<\/code>變量的版本未定義。

為了解決這個問題,您可以將草圖使用的任何局部變量變成狀態變量。 在本例中,我將所有本地人打包到一個對象中:

另一種方法是將使用這些局部變量的函數實際制作為狀態變量。 這樣,它們只會在第一次為它的每個實例調用組件函數時被聲明。 這可能有點小技巧,但它的優點是可以快速更新局部變量(如果您在draw()<\/code>函數中更改局部變量,我的理解是您不希望將它們變成狀態變量,因為高頻狀態更新可能會影響性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM