【问题标题】:Add mp3 to React将 mp3 添加到 React
【发布时间】:2019-07-16 03:46:06
【问题描述】:

我在一个使用 Create React App 引导的项目中的 src 文件夹中添加了一个 mp3。我为音频文件 Audio.js 添加了一个组件,我想根据道具 playAlarm 是否为真有条件地播放它。 父 App.js 将 prop 传递给子 Timer.js,子 Timer.js 渲染 Audio.js。

Audio.js 文件给我一个“React”已定义但从未使用过的错误,我不知道为什么。

Audio.js:

import React, { Component } from 'react';

class Audio extends Component {
  constructor() {
    super();
    this.url = "./chime.mp3";
    this.audio = new Audio(this.url);
  }

  render() {

    return (
      this.audio
    );
  }
}

export default Audio;

在 Timer.js 中,音频是这样渲染的:{props.playAlarm ? <Audio /> : null}

当我测试播放音频时,当 playAlarm 设置为 true 时,我得到 Uncaught RangeError: Maximum call stack size exceeded at the line with super() in Audio.js。

App.js:

import React, { Component } from 'react';
import Timer from './Timer';

class App extends Component {
  // ES6 class property/class field syntax allows you to remove constructor when just being used to initialize state
  state = {
    sessionDuration: 5, // TODO: change back to 1500 when testing done
    breakDuration: 3, // TODO: change back to 300 when testing done
    sessionTimeRemaining: 5, // TODO: change back to 1500 when testing done
    breakTimeRemaining: 3, // TODO: change back to 300 when testing done
    isSession: true,
    timerOn: false,
    sessionNumber: 0,
    playAlarm: false
  }

  // Using property initializer syntax to avoid need to bind, since arrow functions don't create their own this context and use value of enclosing context instead. transform-class-properties Babel plugin necessary to use this syntax (included in Create React App). Refer to https://itnext.io/property-initializers-what-why-and-how-to-use-it-5615210474a3 for more details

  // DURATION CHANGES

  decreaseBreakDuration = () => {
    // Conditional statement prevents decrease when break is at 1 minute
    if (this.state.breakDuration === 60) {
      return undefined;
    } else {
      this.setState({
        breakDuration: this.state.breakDuration - 60
      });
    }
  }

  increaseBreakDuration = () => {
    this.setState({
      breakDuration: this.state.breakDuration + 60
    });
  }

  decreaseSessionDuration = () => {
    // Conditional statement prevents decrease when session is at 5 minutes
    if (this.state.sessionDuration === 300) {
      return undefined;
    } else {
      this.setState({
        sessionDuration: this.state.sessionDuration - 60,
        sessionTimeRemaining: this.state.sessionTimeRemaining - 60
      });
    }
  }

  increaseSessionDuration = () => {
    this.setState({
      sessionDuration: this.state.sessionDuration + 60,
      sessionTimeRemaining: this.state.sessionTimeRemaining + 60
    });
  }

  manageBreak = () => {
    this.setState({
      playAlarm: false
    });
    this.time = setInterval(() => {
      this.setState({
        breakTimeRemaining: this.state.breakTimeRemaining - 1
      });
      if (this.state.breakTimeRemaining === 0) {
        this.handleBreakComplete();
      }
    }, 1000);
  }

  manageSession = () => {
    this.setState({
      playAlarm: false
    });
    // Every 1,000 ms (1 second), subtract 1 (a single second) from displayed sessionTimeRemaining. Assigned to this.time (scoped to entire class) in order to pass it to clearInterval() when pause button is clicked
    this.time = setInterval(() => {
      this.setState({
        sessionTimeRemaining: this.state.sessionTimeRemaining - 1
      });
      if (this.state.sessionTimeRemaining === 0) {
        this.handleSessionComplete();
      }
    }, 1000);
  }

  handleSessionComplete = () => {
    clearInterval(this.time);
    this.setState({
      playAlarm: true,
      sessionNumber: this.state.sessionNumber + 1
    })

    if (this.state.sessionNumber === 4) {
      this.handlePomodoroCycleDone();
    } else {
      this.setState({
        timerOn: false,
        sessionTimeRemaining: this.state.sessionDuration,
        breakTimeRemaining: this.state.breakDuration,
        isSession: !this.state.isSession,
      });
    }
  }

  handlePomodoroCycleDone = () => {
    // TODO: Display message in modal
    console.log('Great work! You finished a pomodoro cycle (four sessions). Time to relax.')
    // Change back to default values
    this.setState({
      isSession: true,
      timerOn: false,
      sessionDuration: 5, // TODO: change back to 1500
      breakDuration: 3, // TODO: change back to 300 when testing done
      sessionTimeRemaining: 5, // TODO: change back to 1500
    });
  }

  handleBreakComplete = () => {
    clearInterval(this.time);
    this.setState({
      timerOn: false,
      sessionTimeRemaining: this.state.sessionDuration,
      breakTimeRemaining: this.state.breakDuration,
      isSession: !this.state.isSession,
      playAlarm: true
    });
  }

  // PLAY, PAUSE, RESTART BUTTONS

  startTimer = () => {
    this.setState({
      timerOn: true,
    });

    if (this.state.isSession) {
      this.manageSession();
    } else {
      this.manageBreak();
    }
  }

  pauseTimer = () => {
    // Stops setInterval's calling its (setState) callback every 1000 ms
    clearInterval(this.time);

    this.setState({
      timerOn: false
    });
  }

  resetTimer = () => {
  // Stops setInterval's calling its (setState) callback every 1000 ms
  // TODO: Display 4 unchecked circle icons again
    clearInterval(this.time);
    this.setState({
      timerOn: false,
      sessionDuration: 5, // TODO: change back to 1500
      breakDuration: 3, // TODO: change back to 300 when testing done
      sessionTimeRemaining: 5, // TODO: change back to 1500
      breakTimeRemaining: 3, // TODO: change back to 300 when testing done
      sessionNumber: 0
    });
  }

  render() {
    return (
      <Timer
        breakDuration={this.state.breakDuration}
        sessionDuration={this.state.sessionDuration}

        decreaseBreakDuration={this.decreaseBreakDuration}
        increaseBreakDuration={this.increaseBreakDuration}
        decreaseSessionDuration={this.decreaseSessionDuration}
        increaseSessionDuration={this.increaseSessionDuration}

        sessionTimeRemaining={this.state.sessionTimeRemaining}
        breakTimeRemaining={this.state.breakTimeRemaining}
        timerOn={this.state.timerOn}
        sessionNumber={this.state.sessionNumber}

        isSession={this.state.isSession}

        startTimer={this.startTimer}
        pauseTimer={this.pauseTimer}
        resetTimer={this.resetTimer}

        playAlarm={this.state.playAlarm}
      />
    );
  };
}

导出默认应用;

还有 Timer.js:

import Audio from './Audio';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlay } from '@fortawesome/free-solid-svg-icons';
import { faPause } from '@fortawesome/free-solid-svg-icons';
import { faUndo } from '@fortawesome/free-solid-svg-icons';
import React from 'react';
import PomodoroIcons from './PomodoroIcons';
import DurationControls from './DurationControls';

const TimeFormat = require('hh-mm-ss');

const Timer = props => (

<div className="timer">

  <DurationControls
    breakDuration={props.breakDuration}
    sessionDuration={props.sessionDuration}

    increaseBreakDuration={props.increaseBreakDuration}
    decreaseBreakDuration={props.decreaseBreakDuration}

    increaseSessionDuration={props.increaseSessionDuration}
    decreaseSessionDuration={props.decreaseSessionDuration}
  />

  {/* TIME REMAINING */}
  <p className="time-remaining">
    {props.isSession ? TimeFormat.fromS(props.sessionTimeRemaining) : TimeFormat.fromS(props.breakTimeRemaining)}
  </p>

  {/* PLAY, PAUSE, RESTART BUTTONS */}
  <div className="bottom-btns">

    <div className={props.timerOn ? 'hidden' : ''}>
      <FontAwesomeIcon
        role="button"
        onClick={props.startTimer}
        icon={faPlay}
        className="btn bottom-btn"
        size="4x"
      />
    </div>

    <div className={props.timerOn === false ? 'hidden' : ''}>
      <FontAwesomeIcon
        role="button"
        onClick={props.pauseTimer}
        icon={faPause}
        className="btn bottom-btn"
        size="4x"
      />
    </div>

    <FontAwesomeIcon
      role="button"
      onClick={props.resetTimer}
      icon={faUndo}
      className="btn bottom-btn"
      size="4x"
    />

  </div> {/* End bottom-btns */}

  <PomodoroIcons sessionNumber={props.sessionNumber} />

  {props.playAlarm ? <Audio /> : null}
</div>

);

export default Timer;

【问题讨论】:

  • 尝试在Audio组件constructor(props) { super(props); this.url = "./chime.mp3"; this.audio = new Audio(this.url); }中添加propsconstructorsuper
  • 这不起作用,但感谢您的尝试

标签: javascript reactjs


【解决方案1】:

我不关注这里发生的一切.. 但乍一看这是一个问题:

class Audio extends Component {
  constructor() {
    super();
    this.url = "./chime.mp3";
    this.audio = new Audio(this.url);
  }

  render() {

    return (
      this.audio
    );
  }
}

调用堆栈超出错误是因为您进入了无限循环。您在Audio 内部实例化Audio,这将使另一个Audio 对象等变为无穷大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多