Store and Load Cart State from Local Storage to Persist Cart Data When Reloading the Page

Colby Fayock
InstructorColby Fayock

Share this video with your friends

Send Tweet
Published 3 years ago
Updated 3 years ago

Our cart application is working well. One thing you might have noticed is that if you reload a page, the current state of the application gets wiped out.

This is where Browser Local Storage comes in handy to persist data through refreshes of the application.

This is a side effect that we want to happen any time state changes in our app. React handles this with the useEffect hook. In this hook, we will use the window.localStorage API to set and get cart data in our application.

Instructor: [0:00] We're going to start off with our Space Jelly Shot Next.js App. We're selling three products. If we add those to cart, we can see that our cart in our navigation updates with our global state. To do that, we have a useCart hook, where we're defining cart context and using it to pass in current state all the way through our application.

[0:16] The issue though is if we reload the page, we can see that we immediately lose that state. The issue is when we load that cart state, it only exists in memory, but when we reload the page, that memory gets wiped out.

[0:28] To fix this, we can use the browser's native localStorage API, where we can store structured data and make it available when the page refreshes. Using it, we can both set an item using its ID and later get that item using the same ID.

[0:42] To start, we want to save our cart state anytime that cart state changes. Since we're using the browser API, we want to do it as a side effect. To start, we're going to import the useEffect hook from React. In our application, we're going to use that useEffect hook where we're going to pass in a new function where we're going to create dependencies array where our dependency is our cart.

[1:01] One caveat with localStorage is we need to store it as a string. The first thing we're going to do is we're going to create a new constant called data. We're going to set that equal to JSON.stringify(cart). Then we can access the localStorage with window.localStorage where we can run the setItem method setting an ID. We're going to use spacejelly_cart and the value, which is our data.

[1:23] If we reload the page, we can see that nothing is happening. However, if we open up our developer tools and we navigate to the application tab, if we open up and look under localStorage for our domain, we can see our spacejelly_cart entry.

[1:35] We can also see that if we scroll down to the bottom of the page and add an item to that cart, because our cart state changed, we are now automatically updating that localStorage item. If we reload the page though, we can see that our cart state resets. That's because we're not yet getting that value from our localStorage to make it available in our app.

[1:51] Next, we're going to use the useEffect hook again and add useEffect. This time, I'm going to pass in a new function, but I'm going to add in an empty dependency array, meaning this useEffect hook will only run the first time this useCartState hook is mounted.

[2:04] Let's try to get our localStorage data. We're going to define a new constant called stateFromStorage. We're going to again access the localStorage API from the browser, but this time we're going to getItem and pass in our ID of spaceJellyCart.

[2:17] If we console.log out that value, we can see that when we reload the page, we get that state from storage value. If we add an item to our cart and we again reload the page, we can see that it found our product data.

[2:29] We want to save that data and make it available in our app state. To start, when we save that data, we first use JSON.stringify. We're first going to create a new constant called data where we're first going to check if that state from localStorage variable exists. If it does exist, we're going to run JSON.parse on that data.

[2:47] If that data does exist, we're going to use our updateCart function and pass in our data. If we reload the page and add some items, we can see that we add our items to the cart, but if we reload the page, we still have our cart state.

[3:00] In review, we have our shop where we managed our cart state so that anytime we added an item, it updated in our navigation. However, when we reloaded the page, that cart state would get wiped out.

[3:09] To fix this, we first used an useEffect hook so that any time our cart state change, we're going to stringify that cart state, and we're going to set it in localStorage.

[3:17] Then, we used another useEffect hook, so any time our page loads, we're going to get that cart state from storage where we parsed that string to JSON. If it exists, we update our cart state where now if we go to our store and add some items to our cart, and we try to reload the page, you can see that it saves our cart state.

fauno F
fauno F
~ 3 years ago

thanks master, I'm following this lovely course. then I got a code structure question

  • why do you choose not to use the same '&&' structure like in the code below?
const data = state_from_storage && JSON.parse(state_from_storage)
data && update_cart(data)
Colby Fayock
Colby Fayockinstructor
~ 3 years ago

why do you choose not to use the same '&&' structure like in the code below?

hey @fauno - just personal preference! I like having an explicit if statement wrapped around function invocations

~ 3 years ago

How are you able to implement the function:

         <button onClick={checkout}>
                <a> (subtotal).toFixed(2)} </a>

without returning an error like:

Unhandled Runtime Error

IntegrationError: Client-only Checkout does not support prices with usage_type=metered in items[0].