我有一个组件,它实例化 Tone.js 库中的一些类(例如音频播放器和过滤器),并定义了一些作用于这些对象的函数,这些函数用作一组 UI 渲染按钮中的回调(见下方相关代码)。
其中两个按钮应该使用 useState hook(在 is3D
函数中)切换布尔状态 updateSpatial
以启用/禁用这些按钮之一。但是,此更新显然会导致组件完全重新渲染,从而重新实例化我的类,这会阻止已定义的函数在之后工作。
相比之下,我还尝试了 useRef hook,它允许在不重新渲染的情况下更新 is3D
,但按钮的禁用状态不会更新,因为组件不会重新渲染。
有没有适合这种情况的模式?我的下一次尝试包括使用 HOC、Context 或 Redux,但我不确定这是最直接的。谢谢!
import React, {useState, useEffect, Fragment} from 'react'
import { Player, Destination} from "tone";
const Eagles = () => {
const [is3D, setIs3D] = useState(false);
useEffect(() => {
// connect players to destination, ready to play
connectBase();
});
// Instantiating players
const player1= new Player({
"url": "https://myapp.s3.eu-west-3.amazonaws.com/Aguabeber.m4a",
"autostart": false,
"onload": console.log("player 1 ready")
});
const player2 = new Player({
"url": "https://myapp.s3.eu-west-3.amazonaws.com/Aguas.m4a",
"autostart": false,
"onload": console.log("player 2 ready")
});
// Functions
function connectBase() {
player1.disconnect();
player1.connect(Destination);
player2.disconnect();
player2.chain(Destination);
}
function playStudio() {
player1.volume.value = 0;
player2.volume.value = -60;
}
function playCinema() {
player1.volume.value = -60;
player2.volume.value = 0;
}
function playstereo() {
player1.volume.value = 0;
player2.volume.value = -60;
updateSpatial();
}
function playmyhifi() {
player1.volume.value = -60;
player2.volume.value = 0;
updateSpatial();
}
function start() {
player1.start();
player2.start();
playstereo();
}
function stop() {
player1.stop();
player2.stop();
console.log("stop pressed")
}
// Update state to toggle button enabled`
function updateSpatial() {
setIs3D((is3D) => !is3D);
}
return (
<Fragment>
<ButtonTL onClick={start}>Play</ButtonTL>
<ButtonTR onClick={stop}>Stop</ButtonTR>
<ButtonTL2 onClick={playstereo}>Stereo</ButtonTL2>
<ButtonTR2 onClick={playmyhifi}>3D</ButtonTR2>
<ButtonLL disabled={is3D} onClick={playStudio}>Studio</ButtonLL>
<ButtonLR onClick={playCinema}>Cinema</ButtonLR>
</Fragment>
)
}
答案 0 :(得分:2)
我发现您的代码有两处错误。 首先,函数“正常”主体中的所有内容都将在每次渲染时执行。因此,需要状态和钩子。 状态允许您在渲染之间保留数据,而钩子允许您在状态更改时执行特定操作。
其次,useEffect(()=>console.log(hi))
没有任何依赖关系,因此它会在每次渲染时运行。
useEffect(()=>console.log(hi),[])
将仅在第一次渲染时执行。
useEffect(()=>console.log(hi),[player1])
将在 player1 更改时执行。
useEffect(()=>console.log(hi),[player1, player2])
将在 player1 或 player2 更改时执行。
小心带有依赖项的钩子。如果在钩子本身内设置依赖项之一的状态,它将创建一个无限循环
这里有一些更接近你想要的东西:
import React, {useState, useEffect, Fragment} from 'react'
import { Player, Destination} from "tone";
const Eagles = () => {
const [is3D, setIs3D] = useState(false);
const [player1]= useState(new Player({
"url": "https://myapp.s3.eu-west-3.amazonaws.com/Aguabeber.m4a",
"autostart": false,
"onload": console.log("player 1 ready")
}));
const [player2] = useState(new Player({
"url": "https://myapp.s3.eu-west-3.amazonaws.com/Aguas.m4a",
"autostart": false,
"onload": console.log("player 2 ready")
}));
useEffect(() => {
// connect players to destination, ready to play
connectBase();
},[player1, player2]);
// Instantiating players
// Functions
function connectBase() {
player1.disconnect();
player1.connect(Destination);
player2.disconnect();
player2.chain(Destination);
}
function playStudio() {
player1.volume.value = 0;
player2.volume.value = -60;
}
function playCinema() {
player1.volume.value = -60;
player2.volume.value = 0;
}
function playstereo() {
player1.volume.value = 0;
player2.volume.value = -60;
updateSpatial();
}
function playmyhifi() {
player1.volume.value = -60;
player2.volume.value = 0;
updateSpatial();
}
function start() {
player1.start();
player2.start();
playstereo();
}
function stop() {
player1.stop();
player2.stop();
console.log("stop pressed")
}
// Update state to toggle button enabled`
function updateSpatial() {
setIs3D((is3D) => !is3D);
}
return (
<Fragment>
<ButtonTL onClick={start}>Play</ButtonTL>
<ButtonTR onClick={stop}>Stop</ButtonTR>
<ButtonTL2 onClick={playstereo}>Stereo</ButtonTL2>
<ButtonTR2 onClick={playmyhifi}>3D</ButtonTR2>
<ButtonLL disabled={is3D} onClick={playStudio}>Studio</ButtonLL>
<ButtonLR onClick={playCinema}>Cinema</ButtonLR>
</Fragment>
)
}