微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

更新状态而不渲染整个 React 组件useState

如何解决更新状态而不渲染整个 React 组件useState

我有一个组件,它实例化 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","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 或 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","onload": console.log("player 2 ready")
  }));   

  useEffect(() => {
    // connect players to destination,ready to play
    connectBase();
  },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>
  )
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。