reactjs - 更新状态而不渲染整个 React 组件(useState)
问题描述
我有一个组件,它从Tone.js库中实例化一些类(例如音频播放器和过滤器),并定义了一些作用于这些对象的函数,这些函数用作一组 UI 渲染按钮中的回调(参见下面的相关代码)。
其中两个按钮应该is3D
使用useState 钩子(在updateSpatial
函数中)切换布尔状态,以启用/禁用这些按钮之一。但是,此更新显然会导致组件完全重新渲染,从而重新实例化我的类,这会阻止定义的函数在之后工作。
相比之下,我也尝试了useRef 钩子,它允许在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>
)
}
解决方案
我发现您的代码有两点错误。首先,函数“正常”主体中的所有内容都将在每次渲染时执行。因此,需要状态和钩子。状态允许您在渲染之间保留数据,挂钩允许您在状态更改时执行特定操作。
其次,useEffect(()=>console.log(hi))
没有任何依赖关系,因此它将在每次渲染时运行。
useEffect(()=>console.log(hi),[])
只会在第一次渲染时执行。
useEffect(()=>console.log(hi),[player1])
将在 player1 更改时执行。
useEffect(()=>console.log(hi),[player1, player2])
将在 player1 OR 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>
)
}
推荐阅读
- flutter - IconButton的波纹效果出现在widget下方
- javascript - 我可以将 laravel 应用程序与 Gatsby.js 和 React 编写的静态网站集成吗?
- html - 如何在屏幕中间放置标签
- c - 试图用 C 写一个字母计数器
- angular - 运行业力启动时找不到入口点
- ruby-on-rails - 断开并取消订阅 Action Cable on Rails 6
- debugging - Visual Studio 2019 - 无法调试 Azure 函数 - (桌面 CLR (.NETFramework) 与托管 (CoreCLR) 调试器)
- node.js - 如何修复passport.js中的身份验证功能
- sql - 如何知道 PostgreSQL 和 Oracle 中禁用/启用的索引
- c# - C# 无法从“对象”转换为“System.Net.EndPoint”