如何仅在第一次播放声音 false value after true

How to play a sound only at the first time false value after true

我有包含动态布尔值的人员数据。该值是自动生成的,每次可以为真或假。

网页每5秒获取一次数据并渲染。如果每个人的值都为假,则播放声音。

这是代码:

import React, { Component } from 'react';
import { render } from 'react-dom';
import Sound from './Mp3';

const data = [
  {
    id: '1',
    name: 'Peter',
    value: true
  },
  {
    id: '2',
    name: 'John',
    value: false
  }
];

class App extends Component {
  state = {
    results: [],
  }

  componentDidMount() {
    this.getData()
    // get data every 5 sec
    setInterval(this.getData, 5000);
  }

  getData = () => {
    // generate random value
    data[0].value = Math.random() >= 0.5;
    data[1].value = Math.random() >= 0.5;

    // set results state to data
    this.setState({ results: data });

    // condition if John or Peter value is false
    if (data.some(d => d.value === false)) {
      var audio = new Audio(Sound);
      // play a sound
      audio.play();
    }
  }

  render() {
    const { results } = this.state;
    return (
      <div>
        {results.map(item => {
          return (
            <div key={item.id}>
              <div>
                Name: {item.name}
              </div>
              <div>
                Value: {item.value.toString()}
              </div>
              <br />
            </div>
          )
        })}
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

这是一个demo

使用上面的代码,如果每个人的值都是假的,每次都会播放声音。

如何在true后第一次只播放false值的声音?

我的意思是,如果第一个呈现的 John 值为 false,则播放声音,如果 5 秒后 John 值仍然为 false,则在值恢复为 true 并再次更改为 false 后不播放声音。

我期望的结果:

// first rendered
Name: Peter
Value: true  

Name: John
Value: false  // play a sound

// second (5 seconds later)
Name: Peter
Value: true  

Name: John
Value: false  // don't play a sound

// third (10 seconds later)
Name: Peter
Value: true  

Name: John
Value: true  // don't play a sound

// fourth (15 seconds later)
Name: Peter
Value: true  

Name: John
Value: false  // play a sound

...

您可以使用一种 "Circuit Breaker" 来跟踪其状态以及是否已启用。跳闸后,它会等待一段时间再重新启用。

下面的代码演示了以下内容

  • true 切换到 false 执行 action 回调
  • 继续脉冲false不重复此动作
  • 切换到 true,然后等待比 timeout 更长的时间,然后再次脉冲新的 false 执行 action 回调。

function TFCircuitBreaker(timeout, action){
    this.state = null;
    this.enabled = true;
    
    this.valueChange = function(newValue){
        if(this.enabled){         
          if(this.state && !newValue){
              action();
              this.enabled = false;
              setTimeout( () => this.enabled = true,timeout);
          }
        }
        this.state = newValue;
    }
}

var cb = new TFCircuitBreaker(5000, () => console.log("Play sound"));
cb.valueChange(true);
cb.valueChange(false);
cb.valueChange(true);
cb.valueChange(false);

cb.valueChange(true);
setTimeout( () => cb.valueChange(false), 6000);

我还用类似的代码更新了你的演示,我认为它可以满足你的要求:https://stackblitz.com/edit/react-kmfiij?embed=1&file=index.js

您需要在另一个对象内的 getData 函数之外跟踪每个用户的先前值,然后将先前值与某些对象内的新值进行比较。

  state = {
    results: []
  }

  const previousResults = {};

  componentDidMount() {
    this.getData()
    // get data every 5 sec
    setInterval(this.getData, 5000);
  }

  getData = () => {
    // generate random value
    data[0].value = Math.random() >= 0.5;
    data[1].value = Math.random() >= 0.5;

    // set results state to data
    this.setState({ results: data });

    // condition if user value is false & previous result for user was not false
    if (data.some(d => (d.value === false) && (this.previousResults[d.id] !== false))) {
      var audio = new Audio(Sound);
      // play a sound
      audio.play();
    }

    data.forEach((item) => {
      this.previousResults[item.id] = item.value;
    });
  }