如何在React输入框中同时实现React-Speech-Recognition与搜索功能
问题根源
你之前使用的(inputSearch, transcript)是JavaScript的逗号运算符,它会返回最后一个表达式的值,所以输入框实际只绑定了transcript,键盘输入的inputSearch被完全忽略,导致键盘输入失效、搜索功能异常。
实现方案
要同时支持键盘和语音输入,核心是让同一个状态(inputSearch)同时接收两种输入来源的内容,具体修改如下:
1. 添加useEffect同步语音转录内容
引入useEffect监听transcript的变化,一旦语音识别输出新内容,就更新inputSearch状态:
import React, { useState, useEffect } from "react"; // 新增useEffect导入
// 在组件内部添加 useEffect(() => { if (transcript) { setInputSearch(transcript); } }, [transcript]);
2. 修正麦克风交互逻辑
让麦克风图标支持切换监听状态(点击开始/停止),同时在停止监听时重置转录内容:
const toggleListening = () => { if (listening) { SpeechRecognition.stopListening(); resetTranscript(); } else { SpeechRecognition.startListening({ continuous: true }); // continuous保持持续监听,可选 } };
然后修改麦克风图标点击事件:
<MicSharpIcon className="headerInputMicIcon" onClick={toggleListening} style={{ color: listening ? "#c00" : "inherit" }} // 监听时变色,可选 />
3. 统一状态绑定
输入框和搜索链接只需要绑定inputSearch即可,因为现在这个状态已经整合了键盘和语音输入:
<input onChange={(e) => setInputSearch(e.target.value)} value={inputSearch} placeholder="Search" type="text" /> <Link to={`/search/${inputSearch}`}> <SearchSharpIcon className="headerInputSearchIcon" onClick={handleClick} /> </Link>
修改后的完整代码
import React, { useState, useEffect } from "react"; import "../Header.css"; import MenuSharpIcon from "@mui/icons-material/MenuSharp"; import SearchSharpIcon from "@mui/icons-material/SearchSharp"; import MicSharpIcon from "@mui/icons-material/MicSharp"; import VideoCallOutlinedIcon from "@mui/icons-material/VideoCallOutlined"; import NotificationsNoneSharpIcon from "@mui/icons-material/NotificationsNoneSharp"; import { Avatar } from "@mui/material"; import { Link } from "react-router-dom"; import SpeechRecognition, { useSpeechRecognition, } from "react-speech-recognition"; function Header() { const [inputSearch, setInputSearch] = useState(""); const handleClick = (e) => { if (inputSearch.trim().length < 1) { e.preventDefault(); } setInputSearch(""); }; const { transcript, listening, resetTranscript, browserSupportsSpeechRecognition, } = useSpeechRecognition(); // 同步语音转录内容到inputSearch useEffect(() => { if (transcript) { setInputSearch(transcript); } }, [transcript]); // 切换语音监听状态 const toggleListening = () => { if (listening) { SpeechRecognition.stopListening(); resetTranscript(); } else { SpeechRecognition.startListening({ continuous: true }); } }; if (!browserSupportsSpeechRecognition) { return <span>Browser doesn't support speech recognition.</span>; } return ( <div className="header"> <div className="headerLeft"> <MenuSharpIcon /> <Link to="/"> <img className="headerLogo" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/YouTube_Logo_2017.svg/1024px-YouTube_Logo_2017.svg.png?20220605194644" alt="YouTube Logo" onClick={(e) => setInputSearch("")} /> </Link> </div> <div className="headerInput"> <input onChange={(e) => setInputSearch(e.target.value)} value={inputSearch} placeholder="Search" type="text" /> <Link to={`/search/${inputSearch}`}> <SearchSharpIcon className="headerInputSearchIcon" onClick={handleClick} /> </Link> <MicSharpIcon className="headerInputMicIcon" onClick={toggleListening} style={{ color: listening ? "#ff0000" : "inherit" }} /> </div> <div className="headerRight"> <div className="headerRight1" data-tooltip="Create"> <VideoCallOutlinedIcon className="headerRightIcon" /> </div> <div className="headerRight2" data-tooltip="Notifications"> <NotificationsNoneSharpIcon className="headerRightIcon" /> </div> <div className="headerRight3"> <Avatar className="headerRightIcon">ET</Avatar> </div> </div> </div> ); } export default Header;
额外说明
continuous: true参数让语音识别持续监听,直到手动停止,适合长句输入;如果不需要持续监听,可以去掉该参数,系统会在用户停止说话后自动结束。- 监听时给麦克风图标添加颜色变化,能让用户直观看到当前监听状态。
内容的提问来源于stack exchange,提问作者e-d-i
相关产品推荐
相关产品推荐

