React报错:onTimeUpdate监听器应为函数,实际得到number类型值
问题产生原因
报错的核心原因是你给onTimeUpdate属性传入的值类型不符合要求:
- React的事件属性(比如
onTimeUpdate)要求接收函数类型的监听器,对应事件触发时React才会调用这个函数。 - 你直接写了
onTimeUpdate={setTimeout(initProgressBar, 500, {index})},JSX渲染时会立刻执行setTimeout,把它的返回值(定时器的数字ID,number类型)传给onTimeUpdate,自然会触发「期望得到函数、实际拿到数字」的类型错误。 - 除此之外你的
initProgressBar里还有两个隐藏bug:给开始时间元素赋值时用了currentTime变量,但这个变量是在后面几行才声明的,执行时会触发变量未定义的引用错误;同时每次进度更新都会重复给进度条绑定click监听,会导致点击进度条时多次触发seek逻辑。
修复方案
- 首先修正
onTimeUpdate的传值:把setTimeout逻辑包裹在箭头函数里,把这个箭头函数作为事件监听器传给属性,确保事件触发时才会执行定时器逻辑,而不是渲染时就执行。 - 调整
initProgressBar内部的变量声明顺序,把格式化后当前时间的计算逻辑移到使用它的代码之前,避免引用错误。 - 给DOM元素访问加判空逻辑,避免音频未加载完成、元素未渲染时访问属性抛出错误,同时加标记避免重复绑定事件。
修正后的代码
Audio标签部分
<audio id={`player-${index}`} onTimeUpdate={() => { setTimeout(() => { initProgressBar({index}) }, 500) }} src={`http://127.0.0.1:8000${trackUrl}`} ></audio>
initProgressBar函数部分
const initProgressBar = (num) => { const player = document.getElementById(`player-${num.index}`); // 音频未加载完成时duration为NaN,直接返回等下次更新即可 if (!player || isNaN(player.duration)) return; const length = player.duration; const current_time = player.currentTime; // 提前计算格式化后的当前时间,移到使用位置之前 const currentTimeFormatted = calculateCurrentValue(current_time); const totalLength = calculateTotalValue(length); $(`.end-time-${num.index}`).html(totalLength); $(`.start-time-${num.index}`).html(currentTimeFormatted); const progressbar = document.getElementById(`seekObj-${num.index}`); if (progressbar) { progressbar.value = player.currentTime / player.duration; // 加标记避免重复绑定click事件 if (!progressbar.dataset.seekBound) { progressbar.addEventListener("click", seek); progressbar.dataset.seekBound = "true"; } } if (player.currentTime === player.duration) { $(`#play-btn-${num.index}`).removeClass("pause"); $(`#play-btn-${num.index}`).addClass("button"); } }
注:React项目中长期混用jQuery、原生DOM操作很容易出现状态不同步、内存泄漏问题,后续可以逐步把DOM操作、事件绑定逻辑改成React状态驱动的写法,稳定性会更高。
内容的提问来源于stack exchange,提问作者Volear
相关产品推荐
相关产品推荐

