在 NextJS 中反应自定义 localstorage hook 水合错误

Ale*_*drs 5 javascript typescript reactjs next.js

我试图localstorage在 NextJS 中实现钩子,但出现以下错误:Error: Hydration failed because the initial UI does not match what was rendered on the server.。有什么想法可能导致它吗?在我看来,该功能似乎useEffect没有正确使用。如何强制使用 CSR 而不是 SSR 以避免水合错误?

import { useState, useEffect } from 'react';

function useLocalStorage<T>(key: string, initialValue: T) {
    const [storedValue, setStoredValue] = useState<T>(() => {
        if (typeof window === 'undefined') {
            return initialValue;
        }
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : initialValue;
        } catch (error) {
            return initialValue;
        }
    });

    useEffect(() => {
        setStoredValue(storedValue);
    }, [storedValue, setStoredValue]);

    // eslint-disable-next-line no-unused-vars
    const setValue = (value: T | ((val: T) => T)) => {
        try {
            const valueToStore = value instanceof Function ? value(storedValue) : value;
            setStoredValue(valueToStore);

            if (typeof window !== 'undefined') {
                window.localStorage.setItem(key, JSON.stringify(valueToStore));
            }
        } catch (error) {
            console.log(error);
        }
    };

    return [storedValue, setValue] as const;
}

export default useLocalStorage;

Run Code Online (Sandbox Code Playgroud)

小智 1

我知道有两种方法可以消除水合错误。

首先是使用 next/dynamic 并通过 ssr 选项传递为 false 动态加载,如下所示:

   import dynamic from 'next/dynamic'

   const DynamicHeader = dynamic(() => import('../components/header'), {
     ssr: false,
   })
Run Code Online (Sandbox Code Playgroud)

但由于这是一个自定义挂钩,我们只能动态导入 Component,因此在这种情况下您必须正确使用 useEffect!

其次是使用 useEffect 钩子。我已经在 J​​s 中做到了这一点希望这有帮助!

import { useEffect, useState } from "react";

export default function useLocalStorage(key, initialValue) {
const [value, setValue] = useState();

useEffect(() => {
const data = localStorage.getItem(key);
if (data === null) {
  if (typeof initialValue === "function") {
    setValue(initialValue());
  } else {
    setValue(initialValue);
  }
 } else {
  setValue(JSON.parse(data));
 }
 }, []);

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

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