You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 07:35:20