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

Navigating to the Detail Page With React Router

Navigating to the Detail Page With React Router

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

The product list is in place – now let's connect it to a second view: the product detail page, which we'll fill with all product data starting in chapter 10.

Setting up React Router in main.jsx

src/main.jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
);

Defining routes in App.jsx

src/App.jsx
import { Routes, Route } from 'react-router-dom';
import ProductListPage from './pages/ProductListPage';
import ProductDetailPage from './pages/ProductDetailPage';

function App() {
  return (
    <Routes>
      <Route path="/" element={<ProductListPage />} />
      <Route path="/products/:sku" element={<ProductDetailPage />} />
    </Routes>
  );
}

export default App;

:sku is a dynamic route parameter – Magento's SKU is WELL suited as a URL component here, since unlike an internal database ID, it's also a human-readable, stable identifier outside the app.

components/ProductCard.jsx: a clickable product card

src/components/ProductCard.jsx
import { useNavigate } from 'react-router-dom';

function ProductCard({ product }) {
  const navigate = useNavigate();

  return (
    <li onClick={() => navigate(`/products/${product.sku}`)}>
      {product.name} — {product.price} €
    </li>
  );
}

export default ProductCard;

ProductListPage.jsx: using ProductCard

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

function ProductListPage() {
  const [products, setProducts] = useState([]);
  const [pageCount, setPageCount] = useState(1);
  const [currentPage, setCurrentPage] = useState(1);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    async function load() {
      const result = await fetchProducts({ page: currentPage });
      setProducts(result.products);
      setPageCount(result.pageCount);
      setLoading(false);
    }
    load();
  }, [currentPage]);

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

  return (
    <div>
      <h1>Products</h1>
      <ul>
        {products.map((product) => (
          <ProductCard key={product.sku} product={product} />
        ))}
      </ul>
      <Pagination
        currentPage={currentPage}
        pageCount={pageCount}
        onPageChange={setCurrentPage}
      />
    </div>
  );
}

export default ProductListPage;

pages/ProductDetailPage.jsx: a preliminary skeleton

So the route from this chapter works, let's already create a skeleton – chapter 10 fills it with REAL product data:

src/pages/ProductDetailPage.jsx
import { useParams } from 'react-router-dom';

function ProductDetailPage() {
  const { sku } = useParams();

  return <p>Details for SKU: {sku}</p>;
}

export default ProductDetailPage;

Tipp: Now click a product in the running app – the URL should change to /products/YOUR-SKU, and the still-simple detail page should correctly show the SKU from the URL. EXACTLY this data flow (click → URL changes → useParams() reads the SKU) is the foundation for chapter 10.