【问题标题】:How to enable volume slider of Player tone.js inside of useEffect hook(react)?如何在 useEffect hook(react) 中启用 Playertone.js 的音量滑块?
【发布时间】:2020-12-15 02:23:25
【问题描述】:

我目前正在尝试调整由tone.js 提供的播放器组件的音量。

我启动了一个新的 Player 并利用 useRef 将对象的引用保存在 current 中。

播放器包含 url、循环、音量等键。

在 useEffect 之外,我有一些控制播放和停止方法的事件处理程序,以及一个在 useEffect 内切换循环状态的循环按钮。它们都有效。

我面临的问题是,每当我想调整音量时,都会调用 useEffect,这会导致重新渲染。

我基本上希望能够在创建的 Player 对象中更改音量的关键参数(值)。移动滑块时会重新渲染,但音量不会改变。

我只是把这件事告诉她,希望以前有人这样做过。

我之前的问题没有得到解答,最终我自己解决了。 我认为使用网络音频 API 的人似乎并不多。

我相信,虽然在这种情况下,我只需要一个熟练的反应。

可能有一个简单的解决方法,但我只是缺乏知识。

几周前我开始学习反应。

这是我的代码

import React, { useState, useEffect, useRef} from "react";
import "./DrumMachine.css";
import Button from "./Button";
import { Player } from "tone";
import Sound from "./sound.wav";
import Poti from './Poti';

export default function DrumMachine() {
  console.log("body")
  const [value, setValue ] = useState(0);
  const [loop, setLoop] = useState(false);

  const playerRef = useRef(null);
  playerRef.current = new Player(Sound).toDestination();


  useEffect(() => {
    console.log("useEffect")
    console.log(playerRef.current.volume)
    playerRef.current.loop = loop;
    playerRef.current.volume = value;
  },[loop, value]);
 
  const play = () => {
    playerRef.current.start();
  };

  const stop = () => {
    playerRef.current.stop();
  }

  const volume = (event) => {
    console.log(value)
    setValue(event.target.value)
  }

  const loopToggle = () => {
    console.log('loop')
    setLoop(!loop);
  }
  const doSt = () => {
    console.log('loop')
  }


  return (
    <div className="machine">
      <Button onClick={play}>Play</Button>
      <Button onClick={stop}>Stop</Button>
      <Button onClick={loopToggle}>
        {loop ? 'Loop active' : 'Loop disabled'}
      </Button>
      <Button onClick={doSt}>
        {'Do something'}
      </Button>
      <Button></Button>
      <Button></Button>
      <Button></Button>
      <Button></Button>
      <span className='vol-box'>
        <label htmlFor='vol' >Volume</label>
        <Poti 
        onChange={volume} 
        value={value} id='volM' 
        name='vol' 
        min='0' 
        max='1'
        step='0.1'
        ></Poti>
      </span>
      
    </div>
  );
}

console.logs 显然只是为了测试。我会阅读文档同时希望找到解决方案。

感谢您的帮助。

【问题讨论】:

  • 在 useEffect 中创建 Player 是否有特殊原因?什么会导致这里出现渲染循环?
  • 我遵循了来自tone.js的这个设置:github.com/Tonejs/Tone.js/wiki/Using-Tone.js-with-React-or-Vue。在寻找答案时偶然发现了这篇文章:stackoverflow.com/questions/58170825/…
  • 据我了解,useRef 的变异状态不会导致重新渲染。如果我改变循环的状态并在效果之外启动播放器,它会在每次发生任何变化时重新渲染播放器。如果我错了,请纠正我。
  • 你对 useRef 的看法是对的,但我认为你对 useEffect 的使用有点适得其反。每当循环或值更改时,您的 useEffect 就会执行,这似乎不是您想要的。您是否尝试过将新 Player 保持在 useState 中,并让 useEffect 简单地更新其属性?
  • 你也可以在 useEffect 中做一个简单的条件来检查你的播放器是否已经初始化(定义),如果是,只更新属性。

标签: reactjs react-hooks volume use-effect tone.js


【解决方案1】:

工作叉。

https://codesandbox.io/s/web-audio-api-playground-v2-forked-y1dc6?file=/src/components/DrumMachine.js

好的,有几件事。

  1. 音量最小值和最大值太小,影响不大。我将它设置为 -20 和 20 作为分贝,这足以注意到差异。

  2. 我在组件之外声明了您的播放器,并将其作为 ref 初始值传递给组件。这不是执行此操作的唯一方法,但它是让您的示例正常工作的最简单方法。这使玩家成为单身人士。

如果您需要多个DrumMachine 组件。我建议在自己的组件中创建一个播放器,并传递函数以将其更新为控件组件。这将允许您的控件组件在不同的按钮按下时重新呈现,但您的播放器不会,您可以根据需要拥有任意数量的控件。

【讨论】:

  • 我刚刚就 dB 比例得出了相同的结论......但它只在我停止循环时才有效,即使那样,只是当我点击滑块的新位置时实际上“滑动它。这个沙盒的全部目的只是为了找出如何配置播放器。我的实际项目在 vs 代码中有不同的设置。无论如何我可能会使用外部音量组件。不过这非常有帮助我会听从你的建议。谢谢
猜你喜欢
  • 2019-10-08
  • 1970-01-01
  • 2021-07-04
  • 2020-07-24
  • 2020-09-26
  • 2021-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多