react-use-cart icon indicating copy to clipboard operation
react-use-cart copied to clipboard

Next.js cart storage

Open peckpeck20 opened this issue 4 years ago • 16 comments
trafficstars

Hi!

I'm using the library with Next.js.

When trying to using the library in pages which rendered server-side, the content of the server doesn't match the client. It seems this could be related to the cart being stored using localStorage and this is not available on the server, only in the client.

One thought it to use the storage prop, have you ran into this issue before ?

I tried using the storage prop and the following snipped fails with the following error. Could you provide an example of how the prop should be used and its initial value

function MyApp({ Component, pageProps }) {
  const [cart, setCart] = useState();
  return (
    <div>
      <CartProvider storage={() => [cart, setCart]}>
        <Layout>
          <Component {...pageProps} />;
        </Layout>
      </CartProvider>
    </div>
  );
}

image

peckpeck20 avatar Aug 17 '21 09:08 peckpeck20

I've seen this before, but I haven't figured out a solution yet.

notrab avatar Sep 01 '21 12:09 notrab

Very interested in this!

The might be a solution in this thread: https://www.reddit.com/r/learnreactjs/comments/emtl9c/having_trouble_with_state_and_using_localstorage/

Haven't tried it yet.

debatz avatar Nov 02 '21 19:11 debatz

@debatz I was thinking we could do something like adding:

useEffect(() => setMounted(true), []);

Inside of the CartProvider. It's a cheap way of checking if all is mounted, and if so, we can continue.

notrab avatar Jan 09 '22 09:01 notrab

I haven't used this library yet, but was looking at it, and had found the same error using Uppy with NextJS.

My solution was to wrap the Uppy component with this:

ClientOnly.tsx

import dynamic from "next/dynamic"
import React from "react"

const ClientOnly = props => (
  <React.Fragment>{props.children}</React.Fragment>
)

export default dynamic(() => Promise.resolve(ClientOnly), {
  ssr: false
})

Your approach seems cleaner, adding just for context @notrab

debatz avatar Jan 09 '22 21:01 debatz

Hey, has there been a solution for this yet in NextJS? I'm getting a server and client mismatch on page reload.

mattdjenkinson avatar Feb 24 '22 19:02 mattdjenkinson

@notrab That approach is working for us.

import { Fragment, useEffect, useState } from "react";
import { CartProvider as BaseCartProvider } from "react-use-cart";

export default function CartProvider({ children, ...props }) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => setMounted(true));

  if (mounted) {
    return <BaseCartProvider {...props}>{children}</BaseCartProvider>;
  }

  return <Fragment>{children}</Fragment>;
}

joshuabaker avatar Apr 01 '22 16:04 joshuabaker

I;m trying to use @joshuabaker 's solution but getting an error calling setCartMetadata inside an useEffect hook. Any ideas on how to fix this?

TypeError: setCartMetadata is not a function```

smarquez1 avatar May 18 '22 22:05 smarquez1

@smarquez1 do you have the provider set higher than where you're using that hook?

notrab avatar May 19 '22 07:05 notrab

@notrab yes, I uploaded a project to github with a minimal version of my main project. Here are the important bits:

https://github.com/smarquez1/cart-test/blob/main/components/CartProvider.tsx https://github.com/smarquez1/cart-test/blob/main/pages/_app.tsx https://github.com/smarquez1/cart-test/blob/main/pages/index.tsx

and it's failing here and anywhere I call a useCart() hook

smarquez1 avatar May 19 '22 18:05 smarquez1

This is happening because the initialState doesn’t include placeholder methods for the various setters.

https://github.com/notrab/react-use-cart/blob/f3f5d0216769ed54cdd1d98ec4ead2f6529dd30d/src/index.tsx#L55-L62

Until we mount we only have access to the values defined here, which don’t include noops.

Here’s another hacky workaround…

const noop = () => {};
const { updateCartMetadata = noop } = useCart();

@notrab If you made use of this open-source hook you might save the hassle on the mounting stuff.

joshuabaker avatar Jun 15 '22 15:06 joshuabaker

I used the solution above (https://github.com/notrab/react-use-cart/issues/88#issuecomment-1086117615) for a while, i.e. conditionally rendering CartProvider only once the app is mounted.

However that leads to a couple of issues

  1. it causes a re-render of all all components below MyCartProvider after react hydrates the page - i.e. a re-render of just about the whole app
  2. sometimes trying to use inCart(), isEmpty etc. elsewhere in the app will fail, as CartProvider is not in place

So I think it's better to conditionally render the components/data which depend on the state of the cart instead.

Contrived example based on new react docs:

// _app.jsx
import { CartProvider } from 'react-use-cart'

function Application({ Component, pageProps }) {
  return (
    <CartProvider>
        <Component {...pageProps} />
    </CartProvider>
  )
}

export default Application;

// MyComponent.jsx
import { useCart } from "react-use-cart";
import { useEffect, useState } from "react";

export default function MyComponent() {
  const { totalUniqueItems } = useCart();
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  if (isClient){
    return (
      <p>You have {totalUniqueItems} items in the cart</p>
    )
  }
  else {
    return (
      // stuff which will only render on the server
    )
  }
}

mdj-uk avatar Apr 16 '23 17:04 mdj-uk

i have this same problem, found another package instead that works with nextjs

https://github.com/mcnaveen/cart

monarcode avatar Oct 20 '23 16:10 monarcode

If someone would like to help merge into support for App Router and other React contexts, please let me know. I don't have so much time these days to work on this as I've no sponsorship for this package currently.

notrab avatar Oct 23 '23 07:10 notrab

@notrab I am using the package inside App Router and seems to be working with no problems. Do you know of any issues?

dani-z avatar Dec 16 '23 23:12 dani-z

https://github.com/mcnaveen/cart

That package lacks a lot of features such as updateItemQuantity, and haven't been updated in a while.

iamvinny avatar Feb 06 '24 21:02 iamvinny