React应用中语音录音发送按钮首次点击发送空文件、二次点击才生效问题排查求助
问题原因分析
我一眼就看出问题出在React状态更新的异步特性和你处理发送逻辑的方式上:
- 当你点击「发送录音」按钮调用
submitNewMessage时,你先执行setAttachFile(audioBlob),然后立刻用attachFile创建请求体{ body: newMessage, attachment: attachFile }。但React的setState是异步的,这时候attachFile还是之前的旧值(初始是undefined),所以第一次发送的是空文件。 - 第二次点击时,
attachFile已经被更新成上一次录制的audioBlob,所以才能发送正确的文件——这完全是因为异步更新滞后导致的巧合。
另外,你的useRecorder钩子中,dataavailable事件触发后才会设置audioBlob,而stopRecording调用后,MediaRecorder需要一点时间来触发这个事件,但这不是核心问题,核心还是submit函数里的状态使用错误。
解决方案
我们可以直接修复submitNewMessage函数,不用依赖attachFile这个中间状态,直接使用当前最新的audioBlob:
const submitNewMessage = () => { // 直接用当前的audioBlob,跳过setAttachFile这一步,避免异步问题 const body = { body: newMessage, attachment: audioBlob } handleUpdateLog(log, newMessage, audioBlob) console.log(audioBlob) // handleSubmitNewMessage(log.id, body) }
如果你的业务逻辑确实需要维护attachFile状态,那你需要用useEffect监听attachFile的变化,在它更新后再执行发送逻辑:
// 先修改submit函数,只负责设置状态 const submitNewMessage = () => { setAttachFile(audioBlob) } // 然后添加useEffect监听attachFile的变化 useEffect(() => { if (attachFile) { const body = { body: newMessage, attachment: attachFile } handleUpdateLog(log, newMessage, attachFile) console.log(attachFile) // handleSubmitNewMessage(log.id, body) // 发送后可以重置状态 setAttachFile(null) } }, [attachFile, log, newMessage, handleUpdateLog])
另外,建议你在useRecorder里做一点小优化,确保audioBlob初始值是null而不是空字符串,这样判断起来更清晰:
const [audioBlob, setAudioBlob] = useState(null);
这样修改后,第一次点击发送就能直接拿到最新的录制文件,不会再出现空文件的问题了。
内容的提问来源于stack exchange,提问作者Hashim Tariq
相关产品推荐
相关产品推荐

