在不渲染整个 React 组件的情况下更新状态(useState)
Updating state without rendering the whole React component (useState)
我有一个组件实例化了 Tone.js 库中的一些 类(例如音频播放器和过滤器)并定义了一些作用于这些对象的函数,这些函数在一组 UI 渲染按钮(参见下面的相关代码)。
其中两个按钮应该使用 useState hook(在 updateSpatial
函数中)切换布尔状态 is3D
,以便 enable/disable 这些按钮之一.但是,此更新显然会导致组件完全重新渲染,从而重新实例化我的 类,这会阻止定义的函数在之后工作。
相比之下,我也尝试了 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>
)
}
我发现您的代码有两处错误。
首先,函数“正常”主体中的所有内容都将在每次渲染时执行。因此,需要状态和钩子。
状态允许您在渲染之间保留数据,挂钩允许您在状态更改时执行特定操作。
其次,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>
)
}
我有一个组件实例化了 Tone.js 库中的一些 类(例如音频播放器和过滤器)并定义了一些作用于这些对象的函数,这些函数在一组 UI 渲染按钮(参见下面的相关代码)。
其中两个按钮应该使用 useState hook(在 updateSpatial
函数中)切换布尔状态 is3D
,以便 enable/disable 这些按钮之一.但是,此更新显然会导致组件完全重新渲染,从而重新实例化我的 类,这会阻止定义的函数在之后工作。
相比之下,我也尝试了 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>
)
}
我发现您的代码有两处错误。 首先,函数“正常”主体中的所有内容都将在每次渲染时执行。因此,需要状态和钩子。 状态允许您在渲染之间保留数据,挂钩允许您在状态更改时执行特定操作。
其次,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>
)
}