react-speech-recognition多表单字段语音录入同时触发所有实例如何解决
问题原因
react-speech-recognition 全局共享单例状态:默认所有调用useSpeechRecognition的组件都订阅同一个全局录音实例的状态,调用全局的startListening方法会触发所有组件同步更新录音状态和转写结果,就会出现两个组件同时启动、文本同步填充的问题。
最简解决方法
给每个语音组件分配唯一的id隔离实例,所有录音操作都指定对应id即可,不需要改动现有业务逻辑:
1. 修改ReviewDict组件
import React, { useEffect } from "react"; import { CardContent } from "@mui/material"; import MicIcon from "@mui/icons-material/Mic"; import MicOffIcon from "@mui/icons-material/MicOff"; import SpeechRecognition, {useSpeechRecognition} from "react-speech-recognition"; export const ReviewDict = ({ changeReview }) => { const { transcript, listening, browserSupportsSpeechRecognition, } = useSpeechRecognition({ id: 'review' }); // 分配唯一id useEffect(() => { changeReview(transcript) }, [transcript, changeReview]); if (!browserSupportsSpeechRecognition) { return <span>浏览器不支持语音识别功能。</span>; } return ( <div> <CardContent sx={{ paddingTop: 5, fontSize: 25 }}> <center> {!listening ? ( <span onClick={() => SpeechRecognition.startListening({ id: 'review' })}> <MicIcon fontSize="normal" /> review </span> ) : ( <span onClick={() => SpeechRecognition.stopListening({ id: 'review' })}> <MicOffIcon fontSize="normal" /> </span> )} </center> </CardContent> </div> ); };
2. 修改OrderDict组件
import React, { useEffect } from "react"; import { CardContent } from "@mui/material"; import MicIcon from "@mui/icons-material/Mic"; import MicOffIcon from "@mui/icons-material/MicOff"; import SpeechRecognition, {useSpeechRecognition} from "react-speech-recognition"; export const OrderDict = ({ changeOrder }) => { const { transcript, listening, browserSupportsSpeechRecognition, } = useSpeechRecognition({ id: 'order' }); // 分配和review不同的唯一id useEffect(() => { changeOrder(transcript); }, [transcript, changeOrder]); if (!browserSupportsSpeechRecognition) { return <span>浏览器不支持语音识别功能。</span>; } return ( <div> <CardContent sx={{ paddingTop: 5, fontSize: 25 }}> <center> {!listening ? ( <span onClick={() => SpeechRecognition.startListening({ id: 'order' })}> <MicIcon fontSize="normal" /> order </span> ) : ( <span onClick={() => SpeechRecognition.stopListening({ id: 'order' })}> <MicOffIcon fontSize="normal" /> </span> )} </center> </CardContent> </div> ); };
可选优化(代码复用)
两个语音组件逻辑完全一致,可以封装为通用组件减少重复代码:
// 通用语音录入组件 Dictaphone.jsx import React, { useEffect } from "react"; import { CardContent } from "@mui/material"; import MicIcon from "@mui/icons-material/Mic"; import MicOffIcon from "@mui/icons-material/MicOff"; import SpeechRecognition, {useSpeechRecognition} from "react-speech-recognition"; export const Dictaphone = ({ fieldId, label, onChange }) => { const { transcript, listening, browserSupportsSpeechRecognition, } = useSpeechRecognition({ id: fieldId }); useEffect(() => { onChange(transcript); }, [transcript, onChange]); if (!browserSupportsSpeechRecognition) { return <span>浏览器不支持语音识别功能。</span>; } return ( <div> <CardContent sx={{ paddingTop: 5, fontSize: 25 }}> <center> {!listening ? ( <span onClick={() => SpeechRecognition.startListening({ id: fieldId })}> <MicIcon fontSize="normal" /> {label} </span> ) : ( <span onClick={() => SpeechRecognition.stopListening({ id: fieldId })}> <MicOffIcon fontSize="normal" /> </span> )} </center> </CardContent> </div> ) }
表单中调用方式:
<Dictaphone fieldId="review" label="review" onChange={dictUpdate} /> <Dictaphone fieldId="order" label="order" onChange={orderUpdate} />
内容的提问来源于stack exchange,提问作者Gordon Maloney
相关产品推荐
相关产品推荐

