无法访问Nextjs中的localStorage

问题描述 投票:0回答:1

我无法访问 Nextjs 中的 localStorage。我可以在我的代码中使用它,一切都按预期工作,并且预期工作中不存在错误。然而终端给出了错误:

ReferenceError: localStorage is not defined
    at MainGrid (./app/components/WeightDisplay/MainGrid.tsx:17:96)
   8 |   // Initialize states for preferences and retrieve from local storage
   9 |   const [metricKg, setMetricKg] = useState(
> 10 |     JSON.parse(localStorage.getItem("metricKg") || "") || false
     |               ^
  11 |   );

这是我的代码,没有其他文件导致该问题:

"use client";
import React, { useEffect, useState } from "react";
import Entry from "./Entry";
import useEntryModal from "@/app/hooks/useEntryModal";

const MainGrid = () => {
  // Initialize states for preferences and retrieve from local storage
  const [metricKg, setMetricKg] = useState(
    JSON.parse(localStorage.getItem("metricKg") || "") || false
  );
  const [metricCm, setMetricCm] = useState(
    JSON.parse(localStorage.getItem("metricCm") || "") || false
  );
  const [compactView, setCompactView] = useState(
    JSON.parse(localStorage.getItem("compactView") || "") || false
  );

  let entry = {
    num: 0,
    date: "Apr 4th",
    weight: 52, // kg by default
    waist: 50, // cm by default
    hip: 30, // cm by default
  };

  const entryModal = useEntryModal();

  const toggleWeightUnit = () => {
    setMetricKg((prevMetricKg: any) => !prevMetricKg);
  };

  const toggleLengthUnit = () => {
    setMetricCm((prevMetricCm: any) => !prevMetricCm);
  };

  const toggleViewMode = () => {
    setCompactView((prevCompactView: any) => !prevCompactView);
  };

  // Save preferences to local storage whenever they change
  useEffect(() => {
    localStorage.setItem("metricKg", JSON.stringify(metricKg));
  }, [metricKg]);

  useEffect(() => {
    localStorage.setItem("metricCm", JSON.stringify(metricCm));
  }, [metricCm]);

  useEffect(() => {
    localStorage.setItem("compactView", JSON.stringify(compactView));
  }, [compactView]);

  return (
    <div className="flex flex-col w-[90%] mx-auto p-4 gap-0 text-white">
      <div className="flex flex-col">
        <h1 className="text-7xl milky-walky text-white text-center w-fit mx-auto jura my-6 mb-0 relative">
          Entry History
          <button
            onClick={() => entryModal.onOpen()}
            className="absolute top-[50%] translate-y-[-50%] right-[-5rem] centrion"
          >
            +
          </button>
        </h1>
        <div className="flex space-x-2 gap-0">
          <div className="m-6 flex gap-3 border-r-2 border-neutral-600 py-2 pr-8">
            Lbs
            <label htmlFor="one">
              <input
                id="one"
                type="checkbox"
                onClick={toggleWeightUnit}
                checked={metricKg}
              />
            </label>
            Kgs
          </div>
          <div className="m-6 flex gap-3 border-r-2 border-neutral-600 py-2 pr-8">
            Inch
            <label htmlFor="one">
              <input
                id="one"
                type="checkbox"
                onClick={toggleLengthUnit}
                checked={metricCm}
              />
            </label>
            Cm
          </div>
          {/* View mode toggle */}
          <div className="m-6 flex gap-3  py-2 pl-6">
            Compact
            <label htmlFor="compactToggle">
              <input
                id="compactToggle"
                type="checkbox"
                onClick={toggleViewMode}
                checked={!compactView}
              />
            </label>
            Comfortable
          </div>
        </div>
      </div>
      {/* Apply gap based on the view mode */}
      <div
        className={` bg-neutral-800/75 flex flex-col ${
          compactView ? " py-2" : "gap-0"
        }`}
      >
        <Entry
          entry={entry}
          metricKg={metricKg}
          compactView={compactView}
          metricCm={metricCm}
        />
        <Entry
          entry={entry}
          metricKg={metricKg}
          compactView={compactView}
          metricCm={metricCm}
        />
        <Entry
          entry={entry}
          metricKg={metricKg}
          compactView={compactView}
          metricCm={metricCm}
        />
      </div>
    </div>
  );
};

export default MainGrid;

我尝试添加 useEffect 检查,它会检查 localStorage,如果它不可用,则分配默认值,但它总是说 localStorage 未定义,即使它已定义。

typescript next.js local-storage
1个回答
0
投票

出现该错误是因为客户端和服务器组件都首先在服务器上渲染。 “use client”指令仅告诉接下来该组件包含要在客户端上执行的交互元素。

因此,窗口元素在服务器渲染期间未定义,并且本地存储也不可用。

如果本地存储的每个出现都在 useEffect 挂钩中,即使是现在作为默认值位于 useState 挂钩内的本地存储,它应该可以正常工作。

因此请确保您永远不会在使用效果挂钩之外使用本地存储,然后它应该可以正常工作。

它仍然有效的原因是,它在客户端接管时有效。显示的错误来自服务器端渲染。

© www.soinside.com 2019 - 2024. All rights reserved.