如何在 useEffect hook(react) 中启用 Playertone.js 的音量滑块? [英] How to enable volume slider of Player tone.js inside of useEffect hook(react)?

查看:59
本文介绍了如何在 useEffect hook(react) 中启用 Playertone.js 的音量滑块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

播放器包含网址、循环、音量等键.

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

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

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

我只是把这个发布给她,希望以前有人这样做过.

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

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

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

几周前我开始学习反应.

这是我的代码

import React, { useState, useEffect, useRef} from "react";导入./DrumMachine.css";从./Button"导入按钮;从音"导入{播放器};从./sound.wav"导入声音;从 './Poti' 导入 Poti;导出默认函数 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 = 循环;playerRef.current.volume = 值;},[循环,值]);const play = () =>{playerRef.current.start();};const stop = () =>{playerRef.current.stop();}const volume = (事件) =>{控制台日志(值)设置值(事件.目标.值)}const loopToggle = () =>{console.log('循环')setLoop(!loop);}const doSt = () =>{console.log('循环')}返回 (<div className="machine"><Button onClick={play}>Play</Button><Button onClick={stop}>Stop</Button><Button onClick={loopToggle}>{环形 ?'循环激活':'循环禁用'}</按钮><Button onClick={doSt}>{'做一点事'}</按钮><按钮></按钮><按钮></按钮><按钮></按钮><按钮></按钮><span className='vol-box'><label htmlFor='vol' >Volume</label><波蒂onChange={音量}value={value} id='volM'名称='卷'分钟='0'最大值 ='1'步骤='0.1'></Poti></span>

);}

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

感谢您的帮助.

解决方案

工作叉.

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

好的,有几件事.

  1. 音量 min 和 max 太小,影响不大.我将它设置为 -20 和 20 作为分贝,这足以发现差异.

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

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

I'm currently trying to adjust the volume of a Player component provided by tone.js.

I initiated a new Player and utilized useRef to save a reference of the object in current.

the Player contains keys like url, loop, volume etc.

Outside of the useEffect I have a few eventhandlers which control the play and stop methods as well as a loop button that toggles the state of loop inside useEffect. They all work.

The problem I am facing is that whenever I want to adjust the volume, useEffect is being called, which leads to a rerender.

I basically want to be able to change the key parameter(value) for volume inside the created Player object. When moving the slider react rerenders but the volume doesn't change.

I just put this out her hoping someone has done this before.

My previous question has been left unanswered and eventually I solved it myself. It seems there are just not many people working with the web audio API I assume.

I believe though in this case I just need someone skilled in react.

There's probably an easy workaround but I just lack the knowledge.

I started learning react a couple of weeks ago.

Here is my code

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

The console.logs are obviously just for testing. I will read the docs meanwhile hoping to find solution.

Thanks for any help.

解决方案

Working fork.

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

Okay, so a couple of things.

  1. The volume min and max were too small to have a big impact. I set it -20 and 20 as the decibels and that was enough to notice a difference.

  2. I declared your player outside of the component and passed it into the component as the ref initial value. This isn't the only way to do this, but it was the easiest to get your example working. This makes the player a singleton.

If you need to have multiple DrumMachine components. I recommend creating a player in its own component and passing functions to update it down to a controls component. This will allow your controls component to get rerendered on different button presses, but your player will not and you can have as many of them as needed.

这篇关于如何在 useEffect hook(react) 中启用 Playertone.js 的音量滑块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆