0

I am find problem in persisting data when page is refreshed. I've a file with reducer and actions. I'm using shopify-js-buy sdk for cart of my project. The cart works fine if there is not page refresh but when there is a page refresh cart item data is not persisting. I feel that if I use only open/close state is persisted but other data like subtotal , items, no.of items etc. are not persisting.

this is reducer and action file:

    import { useSelector, useDispatch } from "react-redux"
import Client from "shopify-buy"

// Creates the client with Shopify-Buy and store info

//Example Storefront

 const client = Client.buildClient({
    storefrontAccessToken: "dd4d4dc146542ba7763305d71d1b3d38",
    domain: "graphql.myshopify.com",
 })

const PRODUCTS_FOUND = "shopify/PRODUCTS_FOUND"
const PRODUCT_FOUND = "shopify/PRODUCT_FOUND"
const COLLECTION_FOUND = "shopify/COLLECTION_FOUND"
const CHECKOUT_FOUND = "shopify/CHECKOUT_FOUND"
const SHOP_FOUND = "shopify/SHOP_FOUND"
const ADD_VARIANT_TO_CART = "shopify/ADD_VARIANT_TO_CART"
const UPDATE_QUANTITY_IN_CART = "shopify/UPDATE_QUANTITY_IN_CART"
const REMOVE_LINE_ITEM_IN_CART = "shopify/REMOVE_LINE_ITEM_IN_CART"
const OPEN_CART = "shopify/OPEN_CART"
const CLOSE_CART = "shopify/CLOSE_CART"
const CART_COUNT = "shopify/CART_COUNT"

const initialState = {
    isCartOpen: false,
    cartCount: 0,
    checkout: {},
    products: [],
    featured: [],
    product: {},
    shop: {},
}

export default (state = initialState, action) => {
    switch (action.type) {
        case PRODUCTS_FOUND:
            return { ...state, products: action.payload }
        case PRODUCT_FOUND:
            return { ...state, product: action.payload }
        case COLLECTION_FOUND:
            return { ...state, featured: action.payload }
        case CHECKOUT_FOUND:
            return { ...state, checkout: action.payload }
        case SHOP_FOUND:
            return { ...state, shop: action.payload }
        case ADD_VARIANT_TO_CART:
            return { ...state, checkout: action.payload }
        case UPDATE_QUANTITY_IN_CART:
            return { ...state, checkout: action.payload }
        case REMOVE_LINE_ITEM_IN_CART:
            return { ...state, checkout: action.payload }
        case OPEN_CART:
            return { ...state, isCartOpen: true }
        case CLOSE_CART:
            return { ...state, isCartOpen: false }
        case CART_COUNT:
            return { ...state, cartCount: action.payload }
        default:
            return state
    }
}

// Gets all the products from Shopify
export function getProducts() {
    return (dispatch) => {
        client.product.fetchAll().then((resp) => {
            dispatch({
                type: PRODUCTS_FOUND,
                payload: resp,
            })
        })
    }
}

// Gets individual item based on id
export function getProduct(id) {
    return async (dispatch) => {
        const resp = await client.product.fetch(id)
        dispatch({
            type: PRODUCT_FOUND,
            payload: resp,
        })
        return resp
    }
}


// Creates initial checkout state from Shopify
export function checkout() {
    return (dispatch) => {
        client.checkout.create().then((resp) => {
            dispatch({
                type: CHECKOUT_FOUND,
                payload: resp,
            })
        })
    }
}

// Gets Shopify store information
export function shopInfo() {
    return (dispatch) => {
        client.shop.fetchInfo().then((resp) => {
            dispatch({
                type: SHOP_FOUND,
                payload: resp,
            })
        })
    }
}

// Adds variants to cart/checkout
export function addVariantToCart(checkoutId, lineItemsToAdd) {
    return async (dispatch) => {
        const response = await client.checkout.addLineItems(
            checkoutId,
            lineItemsToAdd
        )
        dispatch({
            type: ADD_VARIANT_TO_CART,
            payload: response,
        })
        return response
    }
}

// Updates quantity of line items in cart and in checkout state
export function updateQuantityInCart(lineItemId, quantity, checkoutId) {
    const lineItemsToUpdate = [
        { id: lineItemId, quantity: parseInt(quantity, 10) },
    ]

    return async (dispatch) => {
        const resp = await client.checkout.updateLineItems(
            checkoutId,
            lineItemsToUpdate
        )
        dispatch({
            type: UPDATE_QUANTITY_IN_CART,
            payload: resp,
        })
        return resp
    }
}

// Removes line item from cart and checkout state
export function removeLineItemInCart(checkoutId, lineItemId) {
    return (dispatch) => {
        client.checkout.removeLineItems(checkoutId, [lineItemId]).then((resp) => {
            dispatch({
                type: REMOVE_LINE_ITEM_IN_CART,
                payload: resp,
            })
        })
    }
}

// To close the cart
export function handleCartClose() {
    return {
        type: CLOSE_CART,
    }
}

// To open the cart
export function handleCartOpen() {
    return {
        type: OPEN_CART,
    }
}

// Set the count of items in the cart
export function handleSetCount(count) {
    return {
        type: CART_COUNT,
        payload: count,
    }
}

// this is exporting reducer file as shopifyState
export { default as shopifyState } from "./Shopify" //this written in another file.

//this store.js

//===================================================================================

import { createStore, combineReducers, applyMiddleware, compose } from "redux"
import thunk from "redux-thunk";
import * as reducers from "../ReduxStore/ShopifyCart";
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';


const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const rootReducer = combineReducers(reducers)

const enhancer = composeEnhancers(applyMiddleware(thunk))

const persistConfig = {
    key: 'root',
    storage,
    stateReconciler: autoMergeLevel2,
}

const persistedReducer = persistReducer(persistConfig, rootReducer)
export const Store = createStore(persistedReducer, undefined, enhancer)
export const PersistStore = persistStore(Store);

//this is index.js

ReactDOM.render(
    <BrowserRouter>
        <Provider store={Store}>
            <PersistGate loading={null} persistor={PersistStore}>
                <React.StrictMode>
                    <App />
                </React.StrictMode>
            </PersistGate>
        </Provider>
    </BrowserRouter>,
    document.getElementById('root')
);


//this file contains code for showing specific product based on input from another file

import React, { useEffect, useState } from "react"
import { useDispatch, useSelector } from 'react-redux';
import { Link } from "react-router-dom"
// import { useShopify } from "../../../../hooks"
import  {addVariantToCart,getProduct,handleCartOpen} from '../../../../ReduxStore/ShopifyCart/Shopify'

export default (props) => {
    const dispatch = useDispatch()
    
    const checkoutState = useSelector(
        (state) => state.shopifyState.checkout
    )
    const product = useSelector(
        (state)=>(state.shopifyState.product)
    )
    const id = props.match.params.productId
    const defaultSize = product.variants && product.variants[0].id.toString()
    const [size, setSize] = useState("")
    const [quantity, setQuantity] = useState(1)

    const description = product.description && product.description.split(".")

    function changeSize(sizeId, quantity) {
        dispatch(handleCartOpen())
        if (sizeId === "") {
            sizeId = defaultSize
            const lineItemsToAdd = [
                { variantId: sizeId, quantity: parseInt(quantity, 10) },
            ]
            const checkoutId = checkoutState.id
            // addVariant(checkoutId, lineItemsToAdd)
            dispatch(addVariantToCart(checkoutId, lineItemsToAdd))
        } else {
            const lineItemsToAdd = [
                { variantId: sizeId, quantity: parseInt(quantity, 10) },
            ]
            const checkoutId = checkoutState.id
            // addVariant(checkoutId, lineItemsToAdd)
            dispatch(addVariantToCart(checkoutId, lineItemsToAdd))
        }
    }

    useEffect(() => {
        (dispatch(getProduct(id)))
    }, [id])

    return (
        <div id="individualProduct">
            <Link className="homeButton button" to={"/Home"}>
                Home
            </Link>
            <div className="Product-wrapper2">
                <div className="Images">
                    {product.images &&
                        product.images.map((image, i) => {
                            return (
                                <img
                                    key={image.id + i}
                                    src={image.src}
                                    alt={`${product.title} product shot`}
                                />
                            )
                        })}
                </div>
                <div className="Product__info">
                    <h2 className="Product__title2">{product.title}</h2>
                    <ul className="Product__description">
                        {description &&
                            description.map((each, i) => {
                                return <li key={`line-description +${i}`}>{each}</li>
                            })}
                    </ul>
                    <div>
                        <label htmlFor={"prodOptions"}>Size</label>
                        <select
                            id="prodOptions"
                            name={size}
                            onChange={(e) => {
                                setSize(e.target.value)
                            }}
                        >
                            {product.variants &&
                                product.variants.map((item, i) => {
                                    return (
                                        <option
                                            value={item.id.toString()}
                                            key={item.title + i}
                                        >{`${item.title}`}</option>
                                    )
                                })}
                        </select>
                    </div>
                    <div>
                        <label>Quantity</label>
                        <input
                            className="quantity"
                            type="number"
                            min={1}
                            value={quantity}
                            onChange={(e) => {
                                setQuantity(e.target.value)
                            }}
                        ></input>
                    </div>
                    <h3 className="Product__price">
                        ${product.variants && product.variants[0].price}
                    </h3>
                    <button
                        className="prodBuy button"
                        onClick={(e) => changeSize(size, quantity)}
                    >
                        Add to Cart
                    </button>
                </div>
            </div>
        </div>
    )
}

//this is cart code
import React, { useEffect } from "react"
import LineItem from "../LineItem/LineItem"
// import { useShopify } from "../../../../hooks"
import { useSelector, useDispatch } from "react-redux"
import {handleCartOpen,handleCartClose,handleSetCount} from '../../../../ReduxStore/ShopifyCart/Shopify'
// import { MdShoppingCart, MdRemoveShoppingCart } from "react-icons/md"

export default (props) => {
    
    const cartStatus = useSelector((appState) => appState.shopifyState.isCartOpen)
    const checkoutState =  useSelector(
        (appState) => appState.shopifyState.checkout
    )
    const dispatch = useDispatch()
    function handleOpen(e) {
        e.preventDefault()
        dispatch(handleCartOpen())
    }

    function handleClose(e) {
        e.preventDefault()
        dispatch(handleCartClose())
    }

    function openCheckout(e) {
        e.preventDefault()
        // window.open(checkoutState.webUrl) // opens checkout in a new window
        window.location.replace(checkoutState.webUrl) // opens checkout in same window
    }

    useEffect(() => {
        const button = document.querySelector("button.App__view-cart")
        if (cartStatus === true) {
            button.classList.add("hide")
        } else {
            button.classList.remove("hide")
        }

        function getCount() {
            let lineItems =
                checkoutState.lineItems && checkoutState.lineItems.length > 0
                    ? checkoutState.lineItems
                    : []
            let count = 0
            lineItems.forEach((item) => {
                count += item.quantity
                return count
            })

            dispatch(handleSetCount(count))
        }

        getCount()
    }, [cartStatus, checkoutState])

    return (
        <div id="cart">
            <div className={`Cart ${cartStatus ? "Cart--open" : ""}`}>
                <div className="App__view-cart-wrapper2">
                    <button className="App__view-cart" onClick={(e) => handleOpen(e)}>
                        {/* <MdShoppingCart /> */}
                    </button>
                </div>
                <header className="Cart__header">
                    <h2>Your cart</h2>
                    <button className="Cart__close" onClick={(e) => handleClose(e)}>
                        {/* <MdRemoveShoppingCart /> */}
                        <span style={{fontSize: '30px'}}>X</span>
                    </button>
                </header>
                <ul className="Cart__line-items">
                    <LineItem />
                </ul>
                <footer className="Cart__footer">
                    <div className="Cart-info clearfix">
                        <div className="Cart-info__total Cart-info__small">Subtotal</div>
                        <div className="Cart-info__pricing">
                            <span className="pricing">$ {checkoutState.subtotalPrice}</span>
                        </div>
                    </div>
                    <div className="Cart-info clearfix">
                        <div className="Cart-info__total Cart-info__small">Taxes</div>
                        <div className="Cart-info__pricing">
                            <span className="pricing">$ {checkoutState.totalTax}</span>
                        </div>
                    </div>
                    <div className="Cart-info clearfix">
                        <div className="Cart-info__total Cart-info__small">Total</div>
                        <div className="Cart-info__pricing">
                            <span className="pricing">$ {checkoutState.totalPrice}</span>
                        </div>
                    </div>
                    <button
                        className="Cart__checkout button"
                        onClick={(e) => openCheckout(e)}
                    >
                        Checkout
                    </button>
                </footer>
            </div>
        </div>
    )
}
I'm working on reactJs. Will be thankfull for any help on this .
  • Possible duplicate of [this post](https://stackoverflow.com/questions/37195590/how-can-i-persist-redux-state-tree-on-refresh) – Jamie_D Nov 25 '21 at 11:52
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Community Nov 29 '21 at 22:28

0 Answers0