Learn to construct a Magento 2 class web page utilizing ReactJs in a headless growth surroundings.
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 assist you combine the Magento 2 backend with React.
Unlocking a extra versatile and dynamic person expertise and harnessing the complete potential of headless commerce.
Introduction
Making a class web page in React on your Magento 2 retailer can considerably affect person engagement and encourage guests to discover varied product listings.
For a complete information on organising product pages, take a look at our weblog, How you can 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 growth, studying find out how to:
- Fetch knowledge from the Magento 2 GraphQL API
- Handle software state successfully
- Design a responsive format that enhances the general buying expertise
By the top of this information, you’ll have the abilities to create a dynamic and fascinating 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 Mandatory 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 on 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 $type: ProductAttributeSortInput ) { merchandise( filter: $filter pageSize: $pageSize currentPage: $currentPage type: $type ) { 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 } } gadgets { media_gallery { disabled label url place } review_count rating_summary url_key uid sku identify 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 } } } } options { search } } } `;
2. Created a fetch handler in reactjs:
For reusability created a fetch handler operate in file known as FetchHandler.ts.
// src/api/graphql.js export const fetchGraphQL = (question, variables) => { return fetch("https://m243.winterroot.com/graphql", { technique: "POST", headers: { "Content material-Sort": "software/json", }, physique: JSON.stringify({ question, variables }), }) .then((response) => response.json()) .then((consequence) => { if (consequence.errors) { throw new Error(consequence.errors.map((err) => err.message).be part of(", ")); } return consequence.knowledge; }); };



3. Render Class Web page In Your React Software
Create Your Class Web page Element
mkdir src/parts/class contact src/parts/class/index.jsx
Subsequent, add the next code to the index.jsx
element:
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 operate 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(knowledge?.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(knowledge?.merchandise?.applied_filters || []); const fetchProduct = async () => { fetchGraphQL(GET_PRODUCT_BY_CATEGORY, { filter, type, currentPage, page_size: parseInt(pageSize) }) .then((res) => null; setProduct(fetchedProduct); setLoading(false); ) .catch((error) => { setLoading(false); console.error("Error fetchin class knowledge:", 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 desired 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")} >
{knowledge?.merchandise?.total_count} gadgets
{Object.entries(filter)?.size > 0 && ( )}{/* */}{knowledge?.merchandise?.total_count} gadgets
{product?.map((i, index) => ())}
4. Add Sidebar Filter Element In Your Class Web page
Create the Sidebar Filter Element
contact src/parts/class/SidebarFilter.jsx
Implement the Filter Element To advertise reusability, create a separate element for the out there filter record primarily based 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 operate 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.cut up("_")?.[0], to: worth?.cut up("_")?.[1] } : { eq: worth }, // Use 'in' for chosen worth vary })); } }; return ({Object.entries(selectedFilters)?.size > 0 && ( )}); }Shoping Choices
{aggregations?.map((aggregation, index) => ())}
Cell View
Filter Checklist In Sidebar

5. Add Chosen Filter Checklist Element In Your Class Web page
Create the Chosen Filter Element
contact src/parts/class/SelectedFilter.jsx
Implement the Chosen Filter Element To advertise reusability, create a separate element for displaying the chosen filters.
This element will embody 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 Purchasing by
{Object.entries(selectedFilters).map(([attributeCode, options]) => (
- {attributeCode.substitute("_", " ")}:{" "} {choices.size > 1 ? choices[1] : choices[0].substitute("_", " - ")}{" "}
))}- Clear All
6. Add Pagination In Your Class Web page
Create the Pagination Element
contact src/parts/class/Pagination.jsx
Implement the Pagination Element To include pagination and web page dimension performance, add the next code to Pagination.jsx
:
import React from "react"; import { ChevronDownIcon } from "./Icons"; export default operate Pagination({ knowledge, currentPage, setCurrentPage, setPageSize, pageSize }) { const productCounts = Array.from( { size: Math.ground(knowledge?.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.ground(maxVisiblePages / 2)); let endPage = Math.min(knowledge?.merchandise?.page_info?.total_pages, startPage + maxVisiblePages - 1); // Regulate startPage if there are usually 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 ( knowledge?.merchandise?.page_info?.total_pages > 1 && () ); }{/* Earlier button */} {currentPage > 1 && ( )} {getPageNumbers().map((web page) => ( ))} {/* Subsequent button */} {currentPage < knowledge?.merchandise?.page_info?.total_pages && ( )}

7. Create Product Card Element
Create A Product Card Element Element For Class Objects
contact src/parts/class/Product.jsx
Implement the Product Card Element To advertise reusability, create a separate element for the product card construction that shall 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 &&
Be taught Extra
}
8. Add Accordion Element For Your Class Web page
Create Accordion Element
contact src/parts/class/Accordion.jsx
Implement the Accordion Element To advertise reusability, create a separate element for the accordion, which shall be used to render varied forms 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 parts you’ve created for the class web page,
it’s important to replace the App.jsx
element. This replace will contain integrating the header and the class web page right into a cohesive format.
import "./App.css"; import Class from "./parts/class/Index"; import Header "./parts/Header"; operate 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 find out how to create a strong buying 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 person interactions.
Key Takeaways:
- State Administration: Leveraging React’s state hooks to handle class knowledge ensures a seamless person expertise.
- GraphQL Integration: Using the Magento 2 GraphQL API for fetching and displaying class info permits for environment friendly knowledge dealing with and suppleness in managing class operations.
By following these ideas and using the parts we’ve mentioned, builders can create an enticing 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 person interface to fulfill your particular enterprise wants.