当前位置: 首页 > 知识库问答 >
问题:

React钩子-当状态更改为相同值时,如何强制使用效果运行?

苏坚成
2023-03-14

所以我正在构建一个鼓垫类型的应用程序,除了这个,几乎所有的东西都在工作。

编辑:把整件事放在codesandbox上,如果有人想看一看:codesandbox.io/s/sleepy-darwin-jc9b5?file=/src/App.js

const [index, setIndex] = useState(0);
const [text, setText] = useState("");
const [theSound] = useSound(drumBank[index].url)   

function playThis(num) {
  setIndex(num)
}

useEffect(()=>{
  if (index !== null) {
    setText(drumBank[index].id);
    theSound(index);
    console.log(index)
  }
}, [index])

当我按下一个按钮时,索引会更改为与该按钮关联的值,然后use效应钩子会从该索引处的数组中播放声音。但是,当我多次按下同一个按钮时,它只播放一次,因为当索引更改为相同值时,useState不会重新呈现应用。

我希望能够多次按下同一按钮,让应用程序重新渲染,因此每次按下按钮时都可以运行useEffect。有人能帮我怎么做吗?

共有2个答案

禄烨然
2023-03-14

这是我能从你的沙盒里找到的。

>

  • 根据文档,每个useSound只是一个声音,所以当试图通过React状态更新索引到声音库中使用时,播放的声音总是至少延迟一个渲染周期。我建议创建一个新的自定义钩子来封装你的9鼓声。

    useDrumBank使用drumbank数组并将9个鼓声实例化为一个数组。

    const useDrumBank = (drumbank) => {
      const [drum0] = useSound(drumbank[0].url);
      const [drum1] = useSound(drumbank[1].url);
      const [drum2] = useSound(drumbank[2].url);
      const [drum3] = useSound(drumbank[3].url);
      const [drum4] = useSound(drumbank[4].url);
      const [drum5] = useSound(drumbank[5].url);
      const [drum6] = useSound(drumbank[6].url);
      const [drum7] = useSound(drumbank[7].url);
      const [drum8] = useSound(drumbank[8].url);
    
      return [drum0, drum1, drum2, drum3, drum4, drum5, drum6, drum7, drum8];
    };
    

    更新组件逻辑,将drumBank数组传递给新的自定义挂钩。

    const sounds = useDrumBank(drumBank);
    

    以下是完整的代码:

    function App() {
      useEffect(() => {
        document.addEventListener("keypress", key);
    
        return () => document.removeEventListener("keypress", key);
      }, []);
    
      const [text, setText] = useState("");
      const sounds = useDrumBank(drumBank);
    
      function playThis(index) {
        drumBank[index]?.id && setText(drumBank[index].id);
        sounds[index]();
      }
    
      function key(e) {
        const index = drumBank.findIndex((drum) => drum.keyTrigger === e.key);
        index !== -1 && playThis(index);
      }
    
      return (
        <div id="drum-machine" className="drumpad-container">
          <div id="display" className="drumpad-display">
            <p>{text}</p>
          </div>
          <button className="drum-pad" id="drum-pad-1" onClick={() => playThis(0)}>
            Q
          </button>
          <button className="drum-pad" id="drum-pad-2" onClick={() => playThis(1)}>
            W
          </button>
          <button className="drum-pad" id="drum-pad-3" onClick={() => playThis(2)}>
            E
          </button>
          <button className="drum-pad" id="drum-pad-4" onClick={() => playThis(3)}>
            A
          </button>
          <button className="drum-pad" id="drum-pad-5" onClick={() => playThis(4)}>
            S
          </button>
          <button className="drum-pad" id="drum-pad-6" onClick={() => playThis(5)}>
            D
          </button>
          <button className="drum-pad" id="drum-pad-7" onClick={() => playThis(6)}>
            Z
          </button>
          <button className="drum-pad" id="drum-pad-8" onClick={() => playThis(7)}>
            X
          </button>
          <button className="drum-pad" id="drum-pad-9" onClick={() => playThis(8)}>
            C
          </button>
        </div>
      );
    }
    

    加载后立即没有声音

    为了用户的利益,浏览器不允许网站产生声音,直到用户与他们互动(例如。通过点击某些东西)。在用户点击、点击或触发某些东西之前,不会产生任何声音。

    让按键持续工作似乎是一个问题,我没有立即想到一个解决方案,但至少在这一点上,按钮点击工作和声音同步播放。

  • 姚臻
    2023-03-14

    您是否考虑过将这些离散状态变量(值类型)组合成单个引用类型状态对象?

    当索引更改时,您只需同时设置整个状态,而不是设置文本的效果。

    只要你确保这是一个新的对象/引用,那么效果就会触发。该效果然后只负责根据当前状态播放声音。

    下面是一些示例代码

    const [state, setState] = useState({ index: 0, text: '', }); 
    const playThis = (num) => { 
        setState({ index: num, text: drumBank[num].id, }); 
    }; 
    useEffect(() => { 
        theSound(state.index); 
    }, [state]);
    
     类似资料:
    • 我有点像: 设置状态仍然是异步,那么等待这个调用完成的最佳方法是什么? 似乎不像那样接受回调。 在上面,我们希望按顺序运行每个setwhater调用。这是否意味着我们需要设置许多不同的useEffect挂钩来复制这种行为?

    • 提前谢了。我有一个状态数组,如下所示。 我需要添加一个项目到状态数组,我发现我们不需要做状态突变。如何使用PrevState设置状态。 如何调用set State以追加此状态数组。 像这样的东西?

    • 问题内容: tldr; 如何模拟或将prop与数组配合使用以强制重置组件? 我正在实现一个显示计时器的组件,并在该组件达到零时执行回调。目的是让回调更新对象列表。后一个组件由新的React钩子 和组成。 该包含在该定时器启动时的基准,而剩余的时间。该套间隔称为每秒钟更新的剩余时间,并检查是否回调应该叫。 该组件并不是要重新安排计时器的时间,或者在间隔达到零时保持间隔不变,而是应该执行回调和空闲。为

    • 我想用React useState钩子设置多个状态值,这样我就可以用useEffect钩子分别更新它们。我有以下代码: 但是当我用React DevTools检查应用程序时,我会看到钩子的多个“状态”值,而不是“订单”、“支付”、“提交”等。

    • 问题内容: 我正在尝试新的React Hooks,并有一个带有计数器的Clock组件,该计数器应该每秒增加一次。但是,该值不会增加到超过一。 问题答案: 原因是传递给的闭包中的回调仅访问第一个渲染器中的变量,而无法访问后续渲染器中的新值,因为第二次未调用。 回调中的值始终为0 。 就像您熟悉的状态挂钩一样,状态挂钩有两种形式:一种是处于更新状态的状态,另一种是将当前状态传入的回调形式。您应该使用第

    • 我正在试用新的反应挂钩,并有一个时钟组件,计数器应该每秒钟增加一次。但是,该值不增加超过1。