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

Next.js 13中使用localStorage致浏览器崩溃的问题排查与修复

Next.js 13 书签功能卡顿/崩溃与504错误排查及修复

一、浏览器/电脑卡顿崩溃的原因及修复

原因分析

  • 重复读写与序列化消耗:三个操作函数中每次点击都重复读取localStorage并执行JSON.parse,判断完成后调用添加/删除函数又会再次读取,频繁的IO和序列化操作在书签数据量大时会严重占用CPU资源。
  • 冗余数据操作:handleRemoveBookmark中filter后额外用map复制每个书签对象,属于无意义的性能浪费。
  • 事件触发引发重复渲染:每次操作都派发bookmarks事件,若多个组件监听该事件并触发重渲染,会累积不必要的渲染开销,最终引发卡顿。
  • 类型模糊的潜在异常:大量any类型可能导致数据结构处理错误,比如误判重复项或遍历异常,间接加剧性能问题。

修复方案

  1. 客户端缓存书签数据:用useState在客户端组件中缓存解析后的书签列表,仅初始化和数据变化时读取localStorage,避免重复IO操作。
  2. 移除冗余数据操作:删除handleRemoveBookmark中多余的map步骤,filter已返回新数组,无需额外复制。
  3. 优化事件触发逻辑:仅在书签数据实际变化时触发事件,减少不必要的组件重渲染。
  4. 添加明确TypeScript类型:替换any为具体接口,避免数据结构错误导致的异常。

二、部署后504网关超时错误的原因及修复

原因分析

504错误源于服务端渲染(SSR)超时,核心问题如下:

  • 组件未标记为客户端组件:Next.js 13 App Router默认组件为服务端组件,无法访问window/localStorage。即使函数中加了typeof window !== 'undefined',未声明'use client'的组件仍可能在服务端编译或执行阶段出现隐性阻塞,导致服务器超时。
  • 服务端意外触发客户端逻辑:若在服务端渲染流程(如服务端组件生命周期、getServerSideProps)中调用了书签操作函数,即使有window判断,也会拖慢服务端渲染速度,最终引发超时。

修复方案

  1. 强制标记为客户端组件:在包含书签函数的组件顶部添加'use client'指令,确保所有与window/localStorage相关的逻辑仅在客户端执行。
  2. 隔离客户端逻辑:将书签操作函数封装在仅客户端执行的模块或钩子中,避免服务端代码引用。
  3. 检查服务端渲染流程:确保服务端渲染阶段未调用任何书签操作函数,所有交互逻辑仅在客户端用户触发时执行。

优化后的完整代码示例

'use client'; // 必须添加,标记为客户端组件

import { useState, useEffect } from 'react';

// 定义明确的类型接口
interface Verse {
  number: {
    inSurah: number;
    inQuran: number;
  };
}

interface SurahData {
  number: number;
  name: string;
  verses: Verse[];
}

interface Bookmark {
  numberSurah: number;
  name: string;
  numberInQuran: number;
  numberInSurah: number;
}

export default function BookmarkComponent() {
  // 客户端缓存书签数据
  const [bookmarks, setBookmarks] = useState<Bookmark[]>([]);

  // 初始化时读取localStorage并监听跨组件更新事件
  useEffect(() => {
    if (typeof window !== 'undefined') {
      const savedBookmarks = JSON.parse(localStorage.getItem('bookmarks') || '[]') as Bookmark[];
      setBookmarks(savedBookmarks);
    }

    const handleBookmarkUpdate = () => {
      const savedBookmarks = JSON.parse(localStorage.getItem('bookmarks') || '[]') as Bookmark[];
      setBookmarks(savedBookmarks);
    };
    window.addEventListener('bookmarks', handleBookmarkUpdate);

    return () => window.removeEventListener('bookmarks', handleBookmarkUpdate);
  }, []);

  // 统一处理书签保存逻辑
  const saveBookmarksToLocalStorage = (newBookmarks: Bookmark[]) => {
    localStorage.setItem('bookmarks', JSON.stringify(newBookmarks));
    setBookmarks(newBookmarks);
    window.dispatchEvent(new Event('bookmarks'));
  };

  const handleAddBookmark = (data: SurahData, id: number) => {
    const newBookmark = data.verses.find((verse) => verse.number.inQuran === id);
    if (!newBookmark) return;

    const { number: { inSurah, inQuran } } = newBookmark;
    const isDuplicate = bookmarks.some((bookmark) => bookmark.numberInQuran === inQuran);
    if (isDuplicate) return;

    const updatedBookmarks = [...bookmarks, {
      numberSurah: data.number,
      name: data.name,
      numberInQuran: inQuran,
      numberInSurah: inSurah,
    }];
    saveBookmarksToLocalStorage(updatedBookmarks);
  };

  const handleRemoveBookmark = (number: number) => {
    const updatedBookmarks = bookmarks.filter((bookmark) => bookmark.numberInQuran !== number);
    saveBookmarksToLocalStorage(updatedBookmarks);
  };

  const handleBookmarkClick = (item: SurahData, number: number) => {
    const isSaved = bookmarks.some((bookmark) => bookmark.numberInQuran === number);
    isSaved ? handleRemoveBookmark(number) : handleAddBookmark(item, number);
  };

  // 组件渲染逻辑
  return (
    <div>
      {/* 你的书签按钮等交互元素 */}
    </div>
  );
}

内容的提问来源于stack exchange,提问作者Said Al - Ghiyats

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:35:17