Learn to construct a Magento 2 cart web page utilizing ReactJs in a headless growth setting.
1. Introduction
2. Setting Up Your Cart Web page With ReactJs
3. Creating Your Cart Web page with ReactJs
4. Creating Your Cart Web page with ReactJs
5. Conclusion
By leverage of Magento 2 and headless structure, By integrating Magento 2 backend with React, permitting for a extra versatile and dynamic person expertise and the total potential of headless commerce.
Introduction
Making a cart web page in React in your Magento 2 retailer can considerably affect whether or not a person decides to purchase your product or transfer on.
This information will take you thru the method of constructing an environment friendly and user-friendly cart web page, that includes code examples and detailed explanations.
You’ll achieve useful insights into React.js growth alongside the best way.
You’ll learn to fetch knowledge from Magento 2 GraphQL API, handle state, and design a responsive structure that enhances the general buying expertise.
Setting Up Your Cart Web page with ReactJs
1. Create Your ReactJs Venture:
Open your terminal and run the next command to create a brand new React.Js Venture
npx create-react-app my-magento-store cd my-magento-store
2. Navigate to root listing:
cd my-magento-store
3. Set up Crucial Packages In Your ReactJs:
As, I created this with Tailwind, Eslint, React router dom, TypeScript so:
// typescript and eslint npm set up -D typescript eslint // tailwind css npm set up -D tailwindcss postcss autoprefixer npx tailwindcss init -p // react router npm set up react-router-dom
Creating Your Cart Web page with ReactJs
1. Set Up GraphQL Queries:
As we’re utilizing Magento 2 GraphQl API. So lets, create a file in your GraphQL queries. This retains your code organized.
mkdir src/elements/cart contact src/elements/cart/queries.ts
export const GET_CART = ` question ($cartId: String!) { cart(cart_id: $cartId) { id total_quantity applied_coupons { code } objects { cartItemId: uid amount product { title sku stock_status description { html } url_key title thumbnail { id: url url label } } costs { worth { forex worth } row_total { forex worth } row_total_including_tax { forex worth } total_item_discount { forex worth } reductions { label quantity { forex worth } } } } shipping_addresses { nation { code label } area { code region_id label } available_shipping_methods { quantity { forex worth } out there carrier_code carrier_title error_message method_code method_title } selected_shipping_method { quantity { forex worth } carrier_title carrier_code method_code } } costs { applied_taxes { quantity { forex worth } label } reductions { quantity { forex worth } label } grand_total { forex worth } subtotal_excluding_tax { forex worth } } } } `; export const CREATE_EMPTY_CART_MUTATION = ` mutation { createEmptyCart } `; export const UPDATE_CART_MUTATION = ` mutation UpdateCartItem($cartId: String!, $cartItems:[CartItemUpdateInput]!) { updateCartItems(enter: { cart_id: $cartId, cart_items:$cartItems }) { cart { id objects { id amount } } } } `; export const DELETE_CART_MUTATION = ` mutation DeleteCartItem($cartId: String!, $itemId: ID!) { removeItemFromCart(enter: { cart_id: $cartId, cart_item_uid: $itemId }) { cart { id objects { id amount } } } } `; export const APPLY_COUPON_MUTATION = ` mutation ApplyCoupon($cartId: String!, $couponCode: String!) { applyCouponToCart(enter: { cart_id: $cartId, coupon_code: $couponCode }) { cart { id applied_coupons { code } } } } `; export const REMOVE_COUPON_MUTATION = ` mutation RemoveCoupon($cartId: String!) { removeCouponFromCart(enter: { cart_id: $cartId}) { cart { id applied_coupons { code } } } } `;
2. Created a fetch handler in reactjs:
For reusability created a fetch handler operate in file referred to as FetchHandler.ts.
// src/element/cart/FetchHandler.ts export interface GraphQLResponse{ knowledge: T; errors?: Array<{ message: string }>; } export const fetchGraphQL = (question: string, variables: File = {}): Promise => { return fetch(YOUR_MAGENTO_ENDPOINT, { technique: "POST", headers: { "Content material-Kind": "software/json", }, physique: JSON.stringify({ question, variables }), }) .then((response) => response.json()) .then((outcome: GraphQLResponse ) => { if (outcome.errors) { throw new Error(outcome.errors.map((err) => err.message).be a part of(", ")); } return outcome.knowledge; }); };
3. Some {custom} hooks to handle cart :
Right here, I managed issues by creating {custom} hooks in accordance with their performance in cart.ts
//custom-hooks to handle cart functionalities import { useEffect, useState } from "react"; import { fetchGraphQL } from "./FetchHandler"; import { APPLY_COUPON_MUTATION, CREATE_EMPTY_CART_MUTATION, DELETE_CART_MUTATION, GET_CART, REMOVE_COUPON_MUTATION, UPDATE_CART_MUTATION, } from "./queries"; interface CreateCartResponse { createEmptyCart: string; } export default operate useCheckoutQuoteFetch() { const [cartId, setCartId] = useState(() => ); const savedItems = localStorage.getItem("cartItems"); const [items, setItems] = useState (() => { return savedItems ? JSON.parse(savedItems) : []; }); const createCart = async () => { fetchGraphQL (CREATE_EMPTY_CART_MUTATION) .then((knowledge) => { if (knowledge.createEmptyCart) { localStorage.setItem("cartId", knowledge.createEmptyCart); setCartId(knowledge.createEmptyCart); } }) .catch((error) => { console.error("Error creating cart:", error.message); }); }; useEffect(() => { if (!cartId) { createCart(); } }); const getCart = async () => { const variables = { cartId: cartId, }; fetchGraphQL<{ cart: { id: string; objects: Array<{ id: string; amount: quantity }> } }>(GET_CART, variables) .then((response) => { const cart = response?.cart; console.log(cart); if (cart) { localStorage.setItem("cartItems", JSON.stringify(cart)); setItems(cart); } }) .catch((error) => { console.error("Error including merchandise to cart:", error.message); }); }; useEffect(() => { getCart(); }, []); useEffect(() => { localStorage.setItem("cartItems", JSON.stringify(objects)); }, [items]); return { cartId, objects, getCart }; } export const useUpdateCartItem = () => { const [cartId, setCartId] = useState (() => ); const updateCartItem = async (itemId: string, amount: string) => { const variables = { cartId, cartItems: [{ cart_item_uid: itemId, quantity: quantity }], }; return fetchGraphQL<{ updateCartItem: { cart: any } }>(UPDATE_CART_MUTATION, variables) .then((knowledge) => { return knowledge.updateCartItem.cart; }) .catch((err) => { console.error("Error updating cart merchandise:", (err as Error).message); }); }; return { cartId, setCartId, updateCartItem }; }; export const useDeleteCartItem = () => { const [cartId, setCartId] = useState (() => ); const { getCart } = useCheckoutQuoteFetch(); const deleteCartItem = (itemId: string) => { const variables = { cartId, itemId, }; return fetchGraphQL<{ removeItemFromCart: { cart: any } }>(DELETE_CART_MUTATION, variables) .then((knowledge) => { getCart(); return knowledge.removeItemFromCart.cart; }) .catch((err) => { console.error("Error deleting cart merchandise:", (err as Error).message); }); }; return { cartId, setCartId, deleteCartItem }; }; export const useApplyCoupon = () => { const [cartId, setCartId] = useState (() => ); const { getCart } = useCheckoutQuoteFetch(); const applyCoupon = (couponCode: string) => { const variables = { cartId, couponCode, }; return fetchGraphQL<{ applyCouponToCart: { cart: any } }>(APPLY_COUPON_MUTATION, variables) .then((knowledge) => { getCart(); return knowledge.applyCouponToCart.cart; }) .catch((err) => { console.error("Error making use of coupon:", (err as Error).message); }); }; return { cartId, setCartId, applyCoupon }; }; export const useRemoveCoupon = () => { const [cartId, setCartId] = useState (() => ); const { getCart } = useCheckoutQuoteFetch(); const removeCoupon = () => { const variables = { cartId, }; return fetchGraphQL<{ removeCouponFromCart: { cart: any } }>(REMOVE_COUPON_MUTATION, variables) .then((knowledge) => { getCart(); return knowledge.removeCouponFromCart.cart; }) .catch((err) => { console.error("Error eradicating coupon:", (err as Error).message); }); }; return { cartId, setCartId, removeCoupon }; };

Cell View
Cart particulars in cellular view

4. Cart Web page UI Element :
On this element, I’ve efficiently managed the buying cart UI and its related functionalities.
It integrates numerous options to supply a seamless and complete buying cart expertise for customers.
import React, { useEffect, useState } from "react"; import UpdateCartForm from "./CartUpdate"; import useCheckoutQuoteFetch, { useDeleteCartItem, useUpdateCartItem } from "./cart"; import ApplyCoupon from "./ApplyCoupon"; export const formatPrice = (worth: quantity, forex: string) => { return worth?.toLocaleString("en-US", { model: "forex", forex, }); }; export default operate Cart() { useCheckoutQuoteFetch(); const [items, setItems] = useState(() => { const cartQuote = localStorage.getItem("cartItems"); return JSON.parse(cartQuote || "{}").objects || []; }); const [cartData, setCartData] = useState(() => { const cartQuote = localStorage.getItem("cartItems"); return JSON.parse(cartQuote || "{}"); }); useEffect(() => { const handleStorageChange = () => { const cartQuote = localStorage.getItem("cartItems"); const cartData = JSON.parse(cartQuote || "{}") || []; setItems(cartData.objects || []); setCartData(cartData); }; handleStorageChange(); window.addEventListener("storage", handleStorageChange); return () => { window.removeEventListener("storage", handleStorageChange); }; }); const [itemData, setItemData] = useState({ qty: "", id: "" }); const { updateCartItem } = useUpdateCartItem(); const handleSubmit = async (occasion: React.FormEvent) => { occasion.preventDefault(); updateCartItem(itemData.id, itemData.qty) .then((updatedCart) => { console.log("Up to date cart:", updatedCart); }) .catch((error) => { console.error("Did not replace cart merchandise:", error); }); }; const { deleteCartItem } = useDeleteCartItem(); const handleDelete = (itemId: string) => { deleteCartItem(itemId) .then((deleteCartItem) => { console.log("Up to date cart after deletion:", deleteCartItem); }) .catch((error) => { console.error("Did not delete cart merchandise:", error); }); }; const costs = cartData?.costs; const selectedMethod = cartData?.shipping_addresses?.[0]?.selected_shipping_method; return (); }Abstract
{costs?.reductions.size > 0 && (Subtotal
{formatPrice(costs?.subtotal_excluding_tax?.worth, costs?.subtotal_excluding_tax?.forex)}
)} {selectedMethod && (Low cost()
{costs?.reductions?.map((merchandise: { quantity: { worth: quantity; forex: string } }, index: quantity) => ({formatPrice(merchandise?.quantity?.worth, merchandise?.quantity?.forex)}
))})}Delivery({selectedMethod?.carrier_title})
{formatPrice(selectedMethod?.quantity?.worth, selectedMethod?.quantity?.forex)}
Order Complete
{formatPrice(costs?.grand_total?.worth, costs?.grand_total?.forex)}
Examine Out with A number of Addresses
5. Replace Cart Merchandise
On this element, I’ve successfully managed the functionalities associated to replace merchandise amount.
import React, { useState } from "react"; interface UpdateCartFormProps { itemId: string; setItemData: any; qty: quantity; } const UpdateCartForm: React.FC= ({ itemId, setItemData, qty }) => { const [quantity, setQuantity] = useState (`${qty}` || "1"); const changeHandler = (e: React.ChangeEvent ) => { setQuantity(e.goal.worth); setItemData({ qty: e.goal.worth, id: itemId }); }; return ( <> changeHandler(e)} min="1" required /> > ); }; export default UpdateCartForm;
6. Coupon Handler:
On this element, I’ve successfully managed the functionalities associated to making use of and eradicating reductions.
This consists of seamless integration of options that enable customers to enter low cost codes, view utilized coupons, and simply toggle their software standing, enhancing the general buying expertise.
import React, { useState } from "react"; import { ChevronDownIcon } from "../Header"; import { useApplyCoupon, useRemoveCoupon } from "./cart"; export default operate ApplyCoupon() { const [viewCoupun, setViewCoupon] = useState(false); const { applyCoupon } = useApplyCoupon(); const cartQuote = localStorage.getItem("cartItems"); const cartData = JSON.parse(cartQuote || "") || []; const [code, setCode] = useState(cartData?.applied_coupons?.[0]?.code || ""); const handleSubmit = () => { applyCoupon(code) .then((coupon) => { console.log("Up to date cart after making use of coupon:", coupon); }) .catch((error) => { console.error("Failed to use coupon:", error); }); }; const { removeCoupon } = useRemoveCoupon(); const handleRemove = () => { removeCoupon() .then((coupon) => { setCode(""); console.log("Up to date cart after eradicating coupon:", coupon); }) .catch((error) => { console.error("Did not take away coupon:", error); }); }; const appliedCoupon = cartData?.applied_coupons?.size > 0 ? true : false; return ( ); }
7. Set Up Routes
Set your app.tsx in src in accordance with your routing construction like this:
import React from "react"; import "./App.css"; import { Route, Routes } from "react-router-dom"; import Cart from "./element/Cart/Cart"; import Header from "./element/Header"; operate App() { return (); } export default App;
{/* Different routes */}
Run Your ReactJs Utility:
Lastly, run your ReactJs app to see your cart web page in motion:
npm begin
Conclusion
On this weblog, we explored the way to create a sturdy buying cart web page utilizing React at the side of the Magento API.
We coated important functionalities, together with managing cart objects, making use of and eradicating coupons, and dynamically updating the cart based mostly on person interactions.
Key takeaways embody:
- State Administration: Leveraging React’s state hooks to handle cart knowledge ensures a seamless person expertise.
- GraphQL Integration: Using Magento 2 GraphQL API for fetching and updating cart info permits for environment friendly knowledge dealing with and suppleness in managing cart operations.
- Consumer Interactions: Implementing {custom} hooks and elements enhances the performance of the buying cart, permitting for options like merchandise updates and coupon administration.
- Native Storage: Managing cart knowledge in native storage allows persistence, guaranteeing customers don’t lose their cart objects upon web page refresh.
By following these rules and using the elements, builders can create an interesting and environment friendly buying cart expertise.
That integrates easily with Magento 2 highly effective e-commerce capabilities.
With this basis, you possibly can additional develop options, enhance efficiency, and refine the person interface to satisfy particular enterprise wants.