You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React 实现本地音频上传播放功能 修复Audio播放后无法暂停问题

问题根因

你代码无法暂停的核心原因是:Audio实例被你放在了组件渲染逻辑中,每次组件触发重渲染(比如调用setButtonName修改按钮文本状态时),都会重新执行整个组件函数,只要audio状态有值,就会创建一个全新的Audio实例,你调用pause操作的是这个从未播放过的新实例,自然不会生效。


修复后完整代码

import React, { useState, useRef, useEffect } from 'react';

const AudioPlay = () => {
  const [buttonName, setButtonName] = useState('Play');
  // 用useRef存储Audio实例,保证全局唯一,不会随渲染重置
  const audioRef = useRef(null);
  // 存储objectURL用于后续清理
  const audioUrlRef = useRef(null);

  const handleClick = () => {
    if (!audioRef.current) return;
    if (buttonName === 'Play') {
      audioRef.current.play();
      setButtonName('Pause');
    } else {
      audioRef.current.pause();
      setButtonName('Play');
    }
  };

  const addFile = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    // 先清理之前的音频资源
    if (audioRef.current) {
      audioRef.current.pause();
      URL.revokeObjectURL(audioUrlRef.current);
    }
    const audioUrl = URL.createObjectURL(file);
    audioUrlRef.current = audioUrl;
    // 仅在上传文件时创建一次Audio实例
    audioRef.current = new Audio(audioUrl);
    setButtonName('Play');
  };

  // 组件卸载时清理资源,避免内存泄漏
  useEffect(() => {
    return () => {
      if (audioRef.current) {
        audioRef.current.pause();
      }
      if (audioUrlRef.current) {
        URL.revokeObjectURL(audioUrlRef.current);
      }
    };
  }, []);

  return (    
    <div>    
       <button onClick={handleClick} disabled={!audioRef.current}>{buttonName}</button>
       <input type='file' accept="audio/*" onChange={addFile} /> 
    </div>
  );
};

export default AudioPlay;

主要改动说明

  • 用useRef存储Audio实例和生成的临时资源链接,保证实例不会随组件重渲染被重新创建,播放和暂停操作的始终是同一个音频对象
  • 仅在上传新音频文件时创建Audio实例,避免重复实例化
  • 新增了资源清理逻辑,切换音频、组件卸载时都会释放之前创建的临时URL,避免内存泄漏
  • 给按钮增加了禁用态、给文件选择框增加了audio/*的类型限制,优化使用体验

内容的提问来源于stack exchange,提问作者Ganesh Lamichhane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 10:30:01