构建Next JS项目时出现‘navigator is not defined’错误
我在Next.js中实现了一个自定义Hook,通过navigator.onLine属性获取网络在线状态,本地开发环境运行完全正常,但执行npm run build命令构建项目时,抛出了‘navigator is not defined’的错误。我清楚这个问题和水合渲染、预渲染机制有关,但尝试了各种已知方案都没能修复,目前有7个使用该Hook的文件都出现了这个错误。
以下是我的自定义Hook代码:
"use client"; import { useEffect, useState } from "react"; const useNetworkStatus = () => { const [isOnline, setOnline] = useState<boolean>(true); const updateNetworkStatus = () => { if (typeof navigator !== 'undefined') { setOnline(navigator.onLine); } }; // 部分浏览器load事件不触发,所以挂载时手动调用一次更新 useEffect(() => { updateNetworkStatus(); }, []); useEffect(() => { window.addEventListener("load", updateNetworkStatus); window.addEventListener("online", updateNetworkStatus); window.addEventListener("offline", updateNetworkStatus); return () => { window.removeEventListener("load", updateNetworkStatus); window.removeEventListener("online", updateNetworkStatus); window.removeEventListener("offline", updateNetworkStatus); }; }, [navigator.onLine]); return { isOnline }; }; export default useNetworkStatus;
问题根源
错误的核心原因是第二个useEffect的依赖项navigator.onLine——在Next.js预渲染过程中,代码会在服务器端执行,此时浏览器的navigator对象不存在,直接访问navigator.onLine会触发"navigator is not defined"错误。
修复方案
修改两个关键地方:
- 将初始状态改为函数式初始化,避免服务器端直接访问
navigator - 移除第二个
useEffect的navigator.onLine依赖项,改用事件监听捕获网络状态变化
修改后的完整代码:
"use client"; import { useEffect, useState } from "react"; const useNetworkStatus = () => { // 函数式初始化,仅在客户端执行时访问navigator const [isOnline, setOnline] = useState<boolean>(() => typeof navigator !== 'undefined' ? navigator.onLine : true ); const updateNetworkStatus = () => { if (typeof navigator !== 'undefined') { setOnline(navigator.onLine); } }; // 初始挂载时更新状态 useEffect(() => { updateNetworkStatus(); }, []); useEffect(() => { window.addEventListener("load", updateNetworkStatus); window.addEventListener("online", updateNetworkStatus); window.addEventListener("offline", updateNetworkStatus); return () => { window.removeEventListener("load", updateNetworkStatus); window.removeEventListener("online", updateNetworkStatus); window.removeEventListener("offline", updateNetworkStatus); }; }, []); // 移除navigator.onLine依赖,事件监听已能捕获状态变化 return { isOnline }; }; export default useNetworkStatus;
修复说明
- 函数式初始状态:
useState的函数式初始化参数只会在组件首次渲染时执行一次,而且在服务器端渲染时,这个函数会判断navigator是否存在,避免直接访问不存在的对象。 - 移除依赖项:网络状态的变化已经通过
online/offline事件监听来捕获,不需要把navigator.onLine作为useEffect的依赖项,这样就能避免服务器端执行时访问navigator引发的错误。
内容的提问来源于stack exchange,提问作者Abdul Ahad
相关产品推荐
相关产品推荐

