获取 ReferenceError:即使添加“使用客户端”后,本地存储也未定义

Big*_*ble 8 javascript reactjs server-side-rendering next.js

我有一个简单的app/components/organisms/Cookies.tsx模态窗口组件,我将其导入到app/page.tsx. 我已'use client'在组件顶部添加了指令,但由于某种原因,我不断收到:

ReferenceError:本地存储未定义

在此输入图像描述

我的代码Cookies.tsx

'use client';
import { useState } from 'react';

const Cookies = () => {
  const localStorageCookies = localStorage.getItem('cookies-accepted');
  const [cookiesAccepted, setCookiesStatus] = useState<boolean>(!!localStorageCookies);

  const acceptCookies = () => {
    localStorage.setItem('cookies-accepted', 'true');
    setCookiesStatus(true);
  }
  
  return (
    <>
      {!cookiesAccepted && (
        <section className="fixed max-w-md p-4 mx-auto bg-white border border-gray-200 left-12 bottom-16  rounded-2xl z-20">
          <h2 className="font-semibold text-gray-800 "> Cookie Notice</h2>

          <p className="mt-4 text-sm text-gray-600">
            We use cookies to ensure that we give you the best experience on our
            website.{' '}
            <a href="#" className="text-blue-500 hover:underline">
              Read cookies policies
            </a>
            .{' '}
          </p>

          <div className="flex items-center justify-between mt-4 gap-x-4 shrink-0">
            <button className="text-xs text-gray-800 underline transition-colors duration-300 hover:text-gray-600 focus:outline-none">
              Manage your preferences
            </button>

            <button
              className=" text-xs bg-gray-900 font-medium rounded-lg hover:bg-gray-700 text-white px-4 py-2.5 duration-300 transition-colors focus:outline-none"
              onClick={acceptCookies}
            >
              Accept
            </button>
          </div>
        </section>
      )}
    </>
  );
};

export default Cookies;
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?我尝试将其放在文件夹Cookies.tsx之外app,但没有帮助。

我正在使用版本 Next.js 版本13.4.1

You*_*mar 13

正如您在渲染中所读到的,实际上,服务器和客户端组件都首先在服务器上渲染,然后以 HTML 形式发送到浏览器(您可以在浏览器的网络选项卡中看到生成的 HTML 文件)。这是文档的引用:

为了优化初始页面加载,Next.js 将使用 React 的 API 在服务器上为客户端和服务器组件呈现静态 HTML 预览。这意味着,当用户第一次访问您的应用程序时,他们将立即看到页面的内容,而无需等待客户端下载、解析和执行客户端组件 JavaScript 包。

两者之间的区别在于,当您添加 时"use client",这意味着该组件包括客户端交互:因此 Next.js 应该发送所需的 JavaScript(例如事件处理程序、效果等)并将其附加到之前显示为普通的组件HTML 组件。

因此,任何特定于浏览器的内容(例如 )localStorage不应在客户端组件主体中调用,而只能在useEffect事件处理程序内部调用......

这应该适用于您的情况:

"use client";

import { useEffect, useState } from "react";

const Cookies = () => {
  const [cookiesAccepted, setCookiesStatus] = useState<boolean | null>(null);

  const acceptCookies = () => {
    localStorage.setItem("cookies-accepted", "true");
    setCookiesStatus(true);
  };

  useEffect(() => {
    const localStorageCookies = localStorage.getItem("cookies-accepted");
    setCookiesStatus(!!localStorageCookies);
  }, []);

  if (cookiesAccepted === null || cookiesAccepted) {
    return null;
  }

  return (
    <section className="fixed max-w-md p-4 mx-auto bg-white border border-gray-200 left-12 bottom-16  rounded-2xl z-20">
      <h2 className="font-semibold text-gray-800 "> Cookie Notice</h2>

      <p className="mt-4 text-sm text-gray-600">
        We use cookies to ensure that we give you the best experience on our website.{" "}
        <a href="#" className="text-blue-500 hover:underline">
          Read cookies policies
        </a>
        .{" "}
      </p>

      <div className="flex items-center justify-between mt-4 gap-x-4 shrink-0">
        <button className="text-xs text-gray-800 underline transition-colors duration-300 hover:text-gray-600 focus:outline-none">
          Manage your preferences
        </button>

        <button
          className=" text-xs bg-gray-900 font-medium rounded-lg hover:bg-gray-700 text-white px-4 py-2.5 duration-300 transition-colors focus:outline-none"
          onClick={acceptCookies}
        >
          Accept
        </button>
      </div>
    </section>
  );
};

export default Cookies;
Run Code Online (Sandbox Code Playgroud)

并且不要尝试typeof window !== "undefined"破解,因为很可能您会收到水合错误

  • 这正是他们应该将它们称为交互式组件而不是客户端组件的原因。当我听到“客户端组件”时,我直觉地认为它们应该只存在于客户端上,尽管现在我知道事实并非如此。 (3认同)