How to fix hydration error with localStorage

82 Views Asked by At

I'm using the shadcn Navbar component on an e-commerce website.But on these links i lose data from cart.

When I use buttons for the login (/login route), register, and the logo (/home), my cart data remains saved. However, when I use that Navbar component, the cart data resets. So, I decided to add localStorage to useContext to save data immediately to localStorage. It works, but I get an error when I navigate using that Navbar, and the errors are: Error: Text content does not match server-rendered HTML. Warning: Text content did not match. Server: "0" Client: "2" Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

There is my code: Provider code:

const CartProvider = ({ children }: Children) => {
  let initialCartState;

  if (typeof window !== "undefined") {
    const storedCart = localStorage.getItem("cart");
    initialCartState = storedCart ? JSON.parse(storedCart) : defaultCartState;
  } else {
    initialCartState = defaultCartState;
  }

  const [cartState, dispatchCartAction] = useReducer(
    cartReducer,
    initialCartState
  );

  const addItemToCartHandler = (item: CartItem) => {
    dispatchCartAction({ type: ActionType.ADD, item: item });
  };

  const removeItemFromCartHandler = (id: string) => {
    dispatchCartAction({ type: ActionType.REMOVE, id: id });
  };

  const updateItemAmountHandler = (id: string, newAmount: number) => {
    dispatchCartAction({
      type: ActionType.UPDATE_VALUE,
      id: id,
      newAmount: newAmount,
    });
  };

  useEffect(() => {
    if (typeof window !== "undefined") {
      localStorage.setItem("cart", JSON.stringify(cartState));
    }
  }, [cartState]);

  const cartContext: CartContextStateType = {
    items: cartState.items,
    totalAmount: cartState.totalAmount,
    addItem: addItemToCartHandler,
    removeItem: removeItemFromCartHandler,
    updateItemAmount: updateItemAmountHandler,
  };

  return (
    <CartContext.Provider value={cartContext}>{children}</CartContext.Provider>
  );
};

export default CartProvider;

export const useCartContext = () => useContext(CartContext);
"use client";

import * as React from "react";
import Link from "next/link";

import { cn } from "@/lib/utils";
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
  navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
import StripeIcon from "@/app/assets/NavbarIcons/StripeIcon";

const components: { title: string; href: string; description: string }[] = [
  {
    title: "League of legends",
    href: "/products?category=League%20of%20legends",
    description:
      "some descript",
  },
           ...
            ...
 ]

const NavbarLinks = () => {
  return (
    <NavigationMenu>
      <NavigationMenuList>
        <NavigationMenuItem>
          <NavigationMenuTrigger className="bg-neutral-900">
            All
          </NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid gap-3 p-4 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
              <li className="row-span-3">
                <NavigationMenuLink asChild>
                  <Link
                    className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
                    href="/online-payments"
                  >
                    <StripeIcon className="h-24 w-24" />
                    <div className="mb-2 mt-4 text-lg font-medium">
                      Online payments
                    </div>
                    <p className="text-sm leading-tight text-muted-foreground">
                      descrpition
                    </p>
                  </Link>
                </NavigationMenuLink>
              </li>
              <ListItem href="/home" title="Home">
                ...
              </ListItem>
         
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <NavigationMenuTrigger className="bg-neutral-900">
            products
          </NavigationMenuTrigger>
          <NavigationMenuContent>
            <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
              {components.map((component) => (
                <ListItem
                  key={component.title}
                  title={component.title}
                  href={component.href}
                >
                  {component.description}
                </ListItem>
              ))}
            </ul>
          </NavigationMenuContent>
        </NavigationMenuItem>
        <NavigationMenuItem>
          <Link href="/special" legacyBehavior passHref>
            <NavigationMenuLink className={navigationMenuTriggerStyle()}>
              Special
            </NavigationMenuLink>
          </Link>
        </NavigationMenuItem>
      </NavigationMenuList>
    </NavigationMenu>
  );
};
0

There are 0 best solutions below