Next.js 使用 SSR 的本地存储问题

J.D*_*Doe 9 reactjs server-side-rendering next.js react-hooks

我有以下自定义挂钩,它将数据存储在本地存储中:

import { useCallback, useEffect, useState } from "react";

export const useLocalStorage = (key, initialValue) => {
  const initialize = (key) => {
    try {
      const item = localStorage.getItem(key);
      if (item && item !== "undefined") {
        return JSON.parse(item);
      }

      localStorage.setItem(key, JSON.stringify(initialValue));
      return initialValue;
    } catch {
      return initialValue;
    }
  };

  const [state, setState] = useState(() => initialize(key)); // problem is here

  const setValue = useCallback(
    (value) => {
      try {
        const valueToStore = value instanceof Function ? value(storedValue) : value;
        setState(valueToStore);
        localStorage.setItem(key, JSON.stringify(valueToStore));
      } catch (error) {
        console.log(error);
      }
    },
    [key, setState]
  );

  const remove = useCallback(() => {
    try {
      localStorage.removeItem(key);
    } catch {
      console.log(error);
    }
  }, [key]);

  return [state, setValue, remove];
};


Run Code Online (Sandbox Code Playgroud)

它显示了以下问题,我用谷歌搜索了它,似乎是由于 Nextjs 尝试在服务器端运行代码并且没有可用的窗口对象。

在此输入图像描述

问题似乎来自我尝试初始化存储数据的行:

const [state, setState] = useState(() => initialize(key));
Run Code Online (Sandbox Code Playgroud)

我尝试将这个逻辑打包在 useEffect 中,以便它只在客户端运行,但我遇到了无法解决的无限循环。

Rah*_*hul 8

import { useCallback, useEffect, useState } from "react";

export const useLocalStorage = (key, initialValue) => {
  const initialize = (key) => {
    try {
      const item = localStorage.getItem(key);
      if (item && item !== "undefined") {
        return JSON.parse(item);
      }

      localStorage.setItem(key, JSON.stringify(initialValue));
      return initialValue;
    } catch {
      return initialValue;
    }
  };

  const [state, setState] = useState(null); // problem is here

  // solution is here....
  useEffect(()=>{
    setState(initialize(key));
  },[]);

  const setValue = useCallback(
    (value) => {
      try {
        const valueToStore = value instanceof Function ? value(storedValue) : value;
        setState(valueToStore);
        localStorage.setItem(key, JSON.stringify(valueToStore));
      } catch (error) {
        console.log(error);
      }
    },
    [key, setState]
  );

  const remove = useCallback(() => {
    try {
      localStorage.removeItem(key);
    } catch {
      console.log(error);
    }
  }, [key]);

  return [state, setValue, remove];
};
Run Code Online (Sandbox Code Playgroud)

window,localStorage,sessionStorage,etc..未在服务器上定义,因此在服务器上访问它们将导致错误。用于useEffect确保这些代码将在客户端执行。


Bob*_*lly 1

也许将初始化移到 useEffect 内部(但是 useState 需要保留在外部)

在 useEffect 中,只有在以下情况下才进行初始化:typeof window !== "undefined"

  • useEffect 仅在客户端运行,因此不需要检查窗口。这不是问题。请参阅拉胡尔答案的评论。 (2认同)