react-speech-recognition识别结果无法同步写入TextField组件问题
问题根因
这是典型的React受控组件状态脱节问题,没有任何玄学:
- 你表单提交读取的是
setSearchField维护的内部状态,但之前直接把输入框value绑定到语音库返回的transcript上,这俩是完全独立的两个状态,没有做同步 - 语音识别更新
transcript的时候,只会修改输入框的显示值,根本没碰你表单存的搜索状态,所以提交的时候拿不到语音识别的内容 - 等你手动敲一个字符触发输入框
onChange事件,才会把当前输入框里显示的(语音内容+你敲的字符)同步到表单状态里,就出现了必须多敲一个字才能带上语音内容提交的现象 - 你代码里写的
document.setSearchField = "Rendering"是纯无效代码,React状态和DOM自定义属性完全不互通,写了不会产生任何作用。 - 直接把
setSearchField传给TextField的onChange也是错误写法:组件回调返回的第一个参数是事件对象,不是输入的字符串,直接存的话会把整个事件对象存到状态里引发其他bug。
修复方案
- 搜索输入框的
value不要直接绑transcript,要绑定你自己表单维护的searchField状态 - 用
useEffect监听transcript变化,每次语音识别结果更新时,主动调用setSearchField把结果同步到表单状态 - 手动输入时单独写处理函数,从事件对象里取输入值再更新状态
- 重置操作要同时清空语音识别缓存和表单搜索状态
修复后的核心代码如下:
// 先引入useEffect import React, { useEffect } from 'react'; function SearchForm({ runSearch, searchField, setSearchField, setAuthorField, setVenue, setBeginDate, setEndDate, setShowGraph, show_loading }) { const { transcript, listening, resetTranscript, browserSupportsSpeechRecognition } = useSpeechRecognition(); // 同步语音识别结果到表单状态 useEffect(() => { if (transcript) { setSearchField(transcript); } }, [transcript, setSearchField]); // 处理手动输入 const handleSearchChange = (e) => { setSearchField(e.target.value); }; return ( <Grid container spacing={2}> <Grid item xs={1} /> <Grid item xs={10}> <Paper elevation={2}> <div className="search-body"> <form onSubmit={runSearch}> <Grid container spacing={2}> <Grid item xs={12}> <div> <p>麦克风状态:{listening ? '开启' : '关闭'}</p> <button onClick={() => SpeechRecognition.startListening({ continuous: false })}>开始录音</button> <button onClick={SpeechRecognition.stopListening}>停止录音</button> <button onClick={() => { resetTranscript(); setSearchField(''); }}>重置内容</button> </div> <TextField id="busca" label="Palavras-chave *" type='text' value={searchField} name='q' variant="outlined" fullWidth InputProps={{ endAdornment: <SearchIcon /> }} InputLabelProps={{ shrink: true }} onChange={handleSearchChange} /> </Grid> </Grid> </form> </div> </Paper> </Grid> </Grid> ) }
额外注意
- 父组件需要把自身维护的
searchField状态通过props传给SearchForm组件,之前只传了setSearchField方法,受控组件必须同时拿到状态值和更新方法才能正常工作 - 给
startListening传{ continuous: false }参数,可以实现识别到用户说话停顿后自动停止录音,使用体验更好
内容的提问来源于stack exchange,提问作者Freddy Minu
相关产品推荐
相关产品推荐

