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

NextJS中useEffect依赖用window报错,如何监听导航类型变化?

问题描述

我需要实现一个函数,当window.performance.getEntriesByType("navigation")[0].type发生变化时执行。尝试用useEffect实现,但出现了“window is not defined”的引用错误,请问该如何实现函数在目标值变化时触发执行?

补充业务场景:玩家可创建房间,其他玩家通过房间ID加入;若房主离开页面则关闭房间,若其他玩家离开则将其移出房间。

相关代码:

useEffect(() => {
    interrupt()
  }, [window.performance.getEntriesByType("navigation")[0].type]);

async function interrupt(){

    if (players && currentRoom && window.performance.getEntriesByType("navigation")[0].type == 'reload') {
        const docRef = doc(db, "versus_ongoing", currentRoom)

        if(players.players[0].user == user.uid){
            deleteDoc(docRef)
        } else {
            await updateDoc(docRef, {
                players: players.players.filter(post => post.host == true)
            })
        }
      } else {
        console.info( "This page is not reloaded");
      }   
}
解决方案

1. 先解决window is not defined错误

在React(尤其是SSR/SSG场景)中,window仅存在于浏览器环境,组件初始化阶段可能处于服务端,直接访问会报错。先做环境判断再获取导航类型:

const getNavigationType = () => {
  if (typeof window === 'undefined') return '';
  const navigationEntry = window.performance.getEntriesByType("navigation")[0];
  return navigationEntry?.type || '';
};

2. 调整监听逻辑,匹配业务需求

页面的导航类型在同一次会话中不会变化,你实际需要的是玩家离开页面时执行逻辑,用beforeunload事件更直接,同时修正useEffect的依赖问题:

import { useEffect, useState } from 'react';

// ... 其他业务代码

const [navigationType, setNavigationType] = useState('');

useEffect(() => {
  // 初始化时获取当前导航类型
  setNavigationType(getNavigationType());

  // 监听页面卸载/刷新事件,触发业务逻辑
  const handlePageUnload = () => {
    interrupt();
  };

  window.addEventListener('beforeunload', handlePageUnload);

  // 组件卸载时移除监听
  return () => {
    window.removeEventListener('beforeunload', handlePageUnload);
  };
}, [players, currentRoom, user.uid]); // 加入interrupt用到的所有外部依赖

async function interrupt() {
  if (!players || !currentRoom) return;
  
  const navType = getNavigationType();
  if (navType === 'reload') {
    const docRef = doc(db, "versus_ongoing", currentRoom);
    if (players.players[0].user === user.uid) {
      await deleteDoc(docRef);
    } else {
      await updateDoc(docRef, {
        players: players.players.filter(post => post.host)
      });
    }
  } else {
    console.info("This page is not reloaded");
  }
}

3. 关键说明

  • 导航类型(reload/navigate/back_forward)在页面加载完成后就固定,同会话内不会变化,所以“监听变化”的逻辑不成立,改用页面卸载事件更贴合业务场景。
  • useEffect的依赖数组必须包含interrupt用到的所有外部变量,避免闭包导致读取旧值的问题。
  • 加入环境判断后,无论是浏览器还是服务端渲染场景,都不会再出现window is not defined错误。

内容的提问来源于stack exchange,提问作者Jaydendev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 21:10:52