NextJS 13集成react-speech-recognition遇Hydration失败问题求助
NextJS 13 中 react-speech-recognition 水化错误解决方法
问题描述
在NextJS 13中使用react-speech-recognition库实现语音识别功能,复制官方示例代码后出现如下错误:
Error: Hydration failed because the initial UI does not match what was rendered on the server.
尝试过将React降级到v18.1版本、删除.next文件夹,均未解决问题。排查相关文档后,确认未直接调用window对象、也不存在标签嵌套错误,但仍无法定位问题根源。
相关代码如下:
'use client' import 'regenerator-runtime/runtime' import React from 'react' import SpeechRecognition, { useSpeechRecognition, } from 'react-speech-recognition' export default function page() { const { transcript, listening, resetTranscript, browserSupportsSpeechRecognition, } = useSpeechRecognition() if (!browserSupportsSpeechRecognition) { return <span>Browser doesn't support speech recognition.</span> } return ( <div> <p>Microphone: {listening ? 'on' : 'off'}</p> <button onClick={SpeechRecognition.startListening}>Start</button> <button onClick={SpeechRecognition.stopListening}>Stop</button> <button onClick={resetTranscript}>Reset</button> <p>{transcript}</p> </div> ) }
问题根源
react-speech-recognition的useSpeechRecognition钩子中,browserSupportsSpeechRecognition的值在服务端渲染时为false(服务端无浏览器环境),但在客户端浏览器支持语音识别时为true,导致服务端与客户端初始渲染的UI结构不一致,触发水化不匹配错误。
解决方案
方案1:使用useEffect延迟客户端状态初始化
通过useState设置初始状态为null,等待客户端挂载后再获取实际支持状态,确保服务端与客户端初始渲染UI一致:
'use client' import 'regenerator-runtime/runtime' import React, { useState, useEffect } from 'react' import SpeechRecognition, { useSpeechRecognition, } from 'react-speech-recognition' export default function page() { const { transcript, listening, resetTranscript, browserSupportsSpeechRecognition, } = useSpeechRecognition() const [isClientReady, setIsClientReady] = useState(null) useEffect(() => { setIsClientReady(browserSupportsSpeechRecognition) }, [browserSupportsSpeechRecognition]) if (isClientReady === null) { return <span>Loading...</span> } if (!isClientReady) { return <span>Browser doesn't support speech recognition.</span> } return ( <div> <p>Microphone: {listening ? 'on' : 'off'}</p> <button onClick={SpeechRecognition.startListening}>Start</button> <button onClick={SpeechRecognition.stopListening}>Stop</button> <button onClick={resetTranscript}>Reset</button> <p>{transcript}</p> </div> ) }
方案2:动态导入库并禁用服务端渲染
使用NextJS的dynamic导入工具,仅在客户端加载react-speech-recognition相关代码:
'use client' import 'regenerator-runtime/runtime' import React from 'react' import dynamic from 'next/dynamic' // 动态导入并禁用SSR const SpeechRecognition = dynamic( () => import('react-speech-recognition').then(mod => mod.default), { ssr: false } ) const useSpeechRecognition = dynamic( () => import('react-speech-recognition').then(mod => mod.useSpeechRecognition), { ssr: false } ) export default function page() { if (!SpeechRecognition || !useSpeechRecognition) { return <span>Loading...</span> } const { transcript, listening, resetTranscript, browserSupportsSpeechRecognition, } = useSpeechRecognition() if (!browserSupportsSpeechRecognition) { return <span>Browser doesn't support speech recognition.</span> } return ( <div> <p>Microphone: {listening ? 'on' : 'off'}</p> <button onClick={SpeechRecognition.startListening}>Start</button> <button onClick={SpeechRecognition.stopListening}>Stop</button> <button onClick={resetTranscript}>Reset</button> <p>{transcript}</p> </div> ) }
内容的提问来源于stack exchange,提问作者JohnPix
相关产品推荐
相关产品推荐

