Discover ways to construct a Magento 2 class web page utilizing ReactJs in a headless improvement setting.
1. Introduction
2. Setting Up Your Class Web page with ReactJs
3. Creating Your Class Web page with ReactJs
4. Conclusion
By leveraging Magento 2 headless structure, this information will show you how to combine the Magento 2 backend with React.
Unlocking a extra versatile and dynamic consumer expertise and harnessing the total potential of headless commerce.
Introduction
Making a class web page in React to your Magento 2 retailer can considerably impression consumer engagement and encourage guests to discover varied product listings.
For a complete information on organising product pages, try our weblog, Learn how to Create a Magento 2 Product Web page in React.
This information will stroll you thru constructing an environment friendly and user-friendly class web page, full with code examples and detailed explanations.
You’ll acquire useful insights into React.js improvement, studying how one can:
- Fetch information from the Magento 2 GraphQL API
- Handle software state successfully
- Design a responsive structure that enhances the general procuring expertise
By the tip of this information, you’ll have the talents to create a dynamic and interesting class web page that elevates your e-commerce platform.
Setting Up Your Class Web page with ReactJs
1. Create Your ReactJs Undertaking:
Open your terminal and run the next command to create a brand new React.Js Undertaking
npx create-react-app my-magento-store cd my-magento-store
2. Navigate to root listing:
cd my-magento-store
3. Set up Needed Packages In Your ReactJs:
//As, I created this with Tailwind so: npm set up -D tailwindcss postcss autoprefixer npx tailwindcss init -p
Creating Your Class Web page with ReactJs
1. Set Up GraphQL Queries:
As we’re utilizing Magento 2 GraphQl API. So lets, create a file to your GraphQL queries. This retains your code organized.
mkdir src/graphql contact src/graphql/queries.js
export const GET_PRODUCT_BY_CATEGORY = ` question( $filter: ProductAttributeFilterInput $pageSize: Int = 12 $currentPage: Int = 1 $kind: ProductAttributeSortInput ) { merchandise( filter: $filter pageSize: $pageSize currentPage: $currentPage kind: $kind ) { page_info { current_page page_size total_pages } total_count aggregations { attribute_code label depend choices { depend label worth } } sort_fields { default choices { label worth } } objects { media_gallery { disabled label url place } review_count rating_summary url_key uid sku title thumbnail { id: url url label } price_range { maximum_price { final_price { forex worth } regular_price { forex worth } } minimum_price { final_price { forex worth } regular_price { forex worth } } } } strategies { search } } } `;
2. Created a fetch handler in reactjs:
For reusability created a fetch handler perform in file known as FetchHandler.ts.
// src/api/graphql.js export const fetchGraphQL = (question, variables) => { return fetch("https://m243.winterroot.com/graphql", { methodology: "POST", headers: { "Content material-Sort": "software/json", }, physique: JSON.stringify({ question, variables }), }) .then((response) => response.json()) .then((outcome) => { if (outcome.errors) { throw new Error(outcome.errors.map((err) => err.message).be part of(", ")); } return outcome.information; }); };
3. Render Class Web page In Your React Software
Create Your Class Web page Element
mkdir src/elements/class contact src/elements/class/index.jsx
Subsequent, add the next code to the index.jsx
part:
import { useEffect, useState } from "react"; import SidebarFilter from "./SidebarFilter"; import { GET_PRODUCT_BY_CATEGORY } from "../../graphql/queries"; import Product from "./Product"; import { ArrowDownIcon, ArrowUpIcon, GridView, ListView, XMarkIcon } from "./Icons"; import { fetchGraphQL } from "./FetchHandler"; import Pagination from "./Pagination"; import SelectedList from "./SelectedFilter"; import Accordion from "./Accordion"; export default perform Class() { const [product, setProduct] = useState(); const [data, setData] = useState({}); const [productView, setProductView] = useState("grid"); const [filter, setFilter] = useState({}); const [loading, setLoading] = useState(true); const [selectedOption, setSelectedOption] = useState(information?.merchandise?.sort_fields.default); const [sort, setSort] = useState({}); const [order, setOrder] = useState("DESC"); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(12); const [openSideBar, setSideBar] = useState(false); const [selectedFilters, setSelectedFilters] = useState(information?.merchandise?.applied_filters || []); const fetchProduct = async () => { fetchGraphQL(GET_PRODUCT_BY_CATEGORY, { filter, kind, currentPage, page_size: parseInt(pageSize) }) .then((res) => ) .catch((error) => { setLoading(false); console.error("Error fetchin class information:", error.message); }); }; const asscendDescend = () => { if (order === "DESC") { setOrder("ASC"); } else { setOrder("DESC"); } }; const handleChange = (occasion) => { const worth = occasion.goal.worth; setSelectedOption(worth); }; useEffect(() => { if (openSideBar) { doc.physique.classList.add("overflow-hidden"); } else { doc.physique.classList.take away("overflow-hidden"); } // Cleanup to take away class on unmount return () => { doc.physique.classList.take away("overflow-hidden"); }; }, [openSideBar]); useEffect(() => { fetchProduct(); }, [filter, sort, order, currentPage, pageSize]); useEffect(() => { if (selectedOption) { setSort({ [selectedOption]: order }); } }, [order, selectedOption]); if (loading) { returnLoading...
; } if (!product) { returnNo product discovered.
; } const removeFilter = (attributeCode) => { setSelectedFilters((prev) => { const { [attributeCode]: _, ...relaxation } = prev; // Destructure to take away the required attribute return relaxation; // Return the remaining filters }); // Replace the filter state to take away the attribute code setFilter((prev) => { const updatedFilter = { ...prev }; delete updatedFilter[attributeCode]; // Take away the attribute if it is empty return updatedFilter; }); }; const resetFilter = () => { setFilter({}); setSelectedFilters([]); }; return ( <>
> ); }setProductView("grid")} className=" rounded-l-sm border-r border-0 hover:bg-gray-300 cursor-pointer border-x-gray-400 w-10 p-2 px-2 shadow shadow-gray-300/80 bg-[#efefef] text-gray-600" >
setProductView("record")} >
{information?.merchandise?.total_count} objects
{Object.entries(filter)?.size > 0 && ( )}{/* */}{information?.merchandise?.total_count} objects
{product?.map((i, index) => ())}
4. Add Sidebar Filter Element In Your Class Web page
Create the Sidebar Filter Element
contact src/elements/class/SidebarFilter.jsx
Implement the Filter Element To advertise reusability, create a separate part for the accessible filter record based mostly on the attributes obtained from the class record API.
Add the next code to SidebarFilter.jsx
:
import Accordion from "./Accordion"; import SelectedList from "./SelectedFilter"; export default perform SidebarFilter({ aggregations, setFilter, setSelectedFilters, selectedFilters, resetFilter, removeFilter, }) { const handleFilterChange = (attributeCode, worth, label) => { if (attributeCode) { setSelectedFilters((prev) => { const currentSelections = prev[attributeCode] || []; const isSelected = currentSelections.contains(worth); // Replace the chosen filters for checkboxes const newSelections = attributeCode === "worth" ? [value] // Just one choice for worth : isSelected ? currentSelections.filter((v) => v !== worth) // Take away if already chosen : [...currentSelections, value, label]; // Add if not chosen return { ...prev, [attributeCode]: newSelections, }; }); // Replace the filter state setFilter((prev) => ({ ...prev, [attributeCode]: attributeCode === "worth" ? { from: worth.break up("_")?.[0], to: worth?.break up("_")?.[1] } : { eq: worth }, // Use 'in' for chosen worth vary })); } }; return ({Object.entries(selectedFilters)?.size > 0 && ( )}); }Shoping Choices
{aggregations?.map((aggregation, index) => ())}
Cellular View
Filter Checklist In Sidebar
5. Add Chosen Filter Checklist Element In Your Class Web page
Create the Chosen Filter Element
contact src/elements/class/SelectedFilter.jsx
Implement the Chosen Filter Element To advertise reusability, create a separate part for displaying the chosen filters.
This part will embrace features for eradicating filters and rendering the filter record. Add the next code to SelectedFilter.jsx
:
import { XMarkIcon } from "./Icons"; const SelectedList = ({ removeFilter, resetFilter, selectedFilters }) => { return (); }; export default SelectedList;Now Procuring by
{Object.entries(selectedFilters).map(([attributeCode, options]) => (
- {attributeCode.change("_", " ")}:{" "} {choices.size > 1 ? choices[1] : choices[0].change("_", " - ")}{" "}
))}- Clear All
6. Add Pagination In Your Class Web page
Create the Pagination Element
contact src/elements/class/Pagination.jsx
Implement the Pagination Element To include pagination and web page measurement performance, add the next code to Pagination.jsx
:
import React from "react"; import { ChevronDownIcon } from "./Icons"; export default perform Pagination({ information, currentPage, setCurrentPage, setPageSize, pageSize }) { const productCounts = Array.from( { size: Math.flooring(information?.merchandise?.total_count / 12) + 1 }, (_, index) => index * 12 ); const handleChangePageSize = (occasion) => { const worth = occasion.goal.worth; setPageSize(worth); }; const handlePageChange = (web page) => { setCurrentPage(web page); }; const getPageNumbers = () => { const pages = []; const maxVisiblePages = 5; // Decide the vary of pages to show let startPage = Math.max(1, currentPage - Math.flooring(maxVisiblePages / 2)); let endPage = Math.min(information?.merchandise?.page_info?.total_pages, startPage + maxVisiblePages - 1); // Regulate startPage if there should not sufficient pages earlier than if (endPage - startPage < maxVisiblePages - 1) { startPage = Math.max(1, endPage - maxVisiblePages + 1); } // Construct the array of web page numbers for (let i = startPage; i <= endPage; i++) { pages.push(i); } return pages; }; return ( information?.merchandise?.page_info?.total_pages > 1 && () ); }{/* Earlier button */} {currentPage > 1 && ( )} {getPageNumbers().map((web page) => ( ))} {/* Subsequent button */} {currentPage < information?.merchandise?.page_info?.total_pages && ( )}
7. Create Product Card Element
Create A Product Card Element Element For Class Gadgets
contact src/elements/class/Product.jsx
Implement the Product Card Element To advertise reusability, create a separate part for the product card construction that might be rendered within the class itemizing.
Add the next code to Product.jsx
:
import { ChartBarIcon, HeartIcon, StarIcon } from "./Icons"; const Product = ({ product, productView }) => { const priceData = product?.price_range?.maximum_price?.final_price; const forex = "USD"; const worth = priceData?.worth; const worth = worth?.toLocaleString("en-US", { model: "forex", forex, }); const listType = productView !== "grid"; return (); }; export default Product;{" "}
{product?.review_count > 0 && ({Array.from({ size: 5 }, (_, index) => { const ratingValue = index + 1; const isFilled = ratingValue <= product.rating_summary / 20; // Assuming rating_summary is out of 100 return
)}; })} {product?.review_count} Evaluations {listType &&
Study Extra
}
8. Add Accordion Element For Your Class Web page
Create Accordion Element
contact src/elements/class/Accordion.jsx
Implement the Accordion Element To advertise reusability, create a separate part for the accordion, which might be used to render varied sorts of filter lists.
Add the next code to Accordion.jsx
:
import { useState } from "react"; import { ChevronDownIcon, ChevronUpIcon } from "./Icons"; const Accordion = ({ youngsters, title }) => { const [open, setOpen] =useState(false); return ( <>> ); }; export default Accordion;setOpen(!open)} className="flex items-center justify-between w-full cursor-pointer">{open && youngsters}{title}
{open ? (
) : ( )}
9. Replace App.jsx Element Of Your React Undertaking
To make sure your React software successfully makes use of the brand new elements you’ve created for the class web page,
it’s important to replace the App.jsx
part. This replace will contain integrating the header and the class web page right into a cohesive structure.
import "./App.css"; import Class from "./elements/class/Index"; import Header "./elements/Header"; perform App() { return ( <>> ); } export default App;
10. Run Your ReactJs Software:
Lastly, run your React.Js app to see your class web page in motion:
npm begin
Conclusion
On this weblog, we explored how one can create a strong procuring class web page utilizing React along side the Magento API.
We coated important functionalities, together with sorting choices, pagination, and dynamic filters that reply to consumer interactions.
Key Takeaways:
- State Administration: Leveraging React’s state hooks to handle class information ensures a seamless consumer expertise.
- GraphQL Integration: Using the Magento 2 GraphQL API for fetching and displaying class data permits for environment friendly information dealing with and suppleness in managing class operations.
By following these ideas and using the elements we’ve mentioned, builders can create an interesting and environment friendly product itemizing expertise.
That integrates easily with Magento 2’s highly effective e-commerce capabilities.
With this basis, you’ll be able to additional improve options, enhance efficiency, and refine the consumer interface to satisfy your particular enterprise wants.