Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Loading the Product List

Loading the Product List

~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

With the integration token safely stored, let's build the app's centerpiece: a central API client file and the first version of the product list with REAL Magento data.

src/api/magentoApi.js: a central API client

ALL of the app's Magento calls go through ONE file – that way the bearer token header is defined in exactly ONE place, instead of being repeated in every component:

src/api/magentoApi.js
const BASE_URL = import.meta.env.VITE_MAGENTO_BASE_URL;
const ACCESS_TOKEN = import.meta.env.VITE_MAGENTO_ACCESS_TOKEN;

async function magentoFetch(path) {
  const response = await fetch(`${BASE_URL}${path}`, {
    headers: {
      Authorization: `Bearer ${ACCESS_TOKEN}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Magento API error: ${response.status}`);
  }

  return response.json();
}

export async function fetchProducts() {
  const data = await magentoFetch('/products?searchCriteria[pageSize]=12');
  return data;
}

Achtung: Note: searchCriteria[pageSize]=12 is deliberately written here WITHOUT URL-encoding the square brackets (unlike in the raw curl call from chapter 3) – the browser/fetch encodes the URL correctly and automatically when actually sending it. You don't need to do that by hand.

pages/ProductListPage.jsx: first version

src/pages/ProductListPage.jsx
import { useEffect, useState } from 'react';
import { fetchProducts } from '../api/magentoApi';

function ProductListPage() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function load() {
      const data = await fetchProducts();
      setProducts(data.items);
      setLoading(false);
    }
    load();
  }, []);

  if (loading) {
    return <p>Loading products...</p>;
  }

  return (
    <div>
      <h1>Products</h1>
      <ul>
        {products.map((product) => (
          <li key={product.sku}>
            {product.name} — {product.price} €
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ProductListPage;
src/App.jsx
import ProductListPage from './pages/ProductListPage';

function App() {
  return <ProductListPage />;
}

export default App;

Restart npm run dev (because of the .env changes from chapter 6) and open the app – you should now see a SIMPLE but REAL list of your Magento product names and prices.

A first look at data quality: price can be missing

Depending on the product type, Magento doesn't ALWAYS return price as a plain number – configurable products, for instance, often have price: 0 at the top level, with the actual price sitting in custom_attributes or only computed via the price index. For this tutorial, we work with simple products, where price is directly usable – a good reminder to check your shop's TEST DATA if prices show up as 0 or null.