dist/codex/salesforce-commerce/skills/react-patterns/SKILL.md
Build React applications for PWA Kit — hooks, composition, SSR, Commerce SDK integration, Chakra UI components, getProps data fetching, and client-side state management. PWA Kit uses React (NOT Remix/Next.js). Use when building PWA Kit storefronts.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins react-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Always fetch the latest official documentation BEFORE building React components:
https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.htmlhttps://developer.salesforce.com/docs/commerce/commerce-sdk-react/guide/getting-started.htmlhttps://github.com/SalesforceCommerceCloud/pwa-kitVerify PWA Kit version, available hooks, getProps API, and routing patterns against current documentation before writing any component code.
WARNING: PWA Kit is a custom React framework built by Salesforce. It has its own SSR implementation, routing, and data fetching patterns. Do NOT use Next.js or Remix patterns -- they will not work.
| Pattern | PWA Kit | Next.js (DO NOT USE) | Remix (DO NOT USE) |
|---|---|---|---|
| Server data fetching | getProps() static method | getServerSideProps | loader() |
| Client routing | React Router (react-router-dom) | File-based routing | File-based routing |
| Deployment | Managed Runtime | Vercel / self-hosted | Vercel / self-hosted |
| Styling | Chakra UI (default) | Any | Any |
| Commerce SDK | Built-in hooks + typed clients | N/A | N/A |
| SSR server | @salesforce/pwa-kit-runtime | Built-in | Built-in |
| Data mutations | Commerce SDK mutation hooks | Server Actions | action() |
| Error boundaries | React error boundaries | error.tsx | ErrorBoundary export |
| API / Pattern | Purpose | Where It Runs |
|---|---|---|
| Component.getProps() | Server-side data fetching (static method on page components) | Server (SSR) |
| useServerContext() | Access req, res during SSR | Server only |
| getConfig() | Read runtime configuration (config/default.js) | Server + Client |
| RouteComponent | Page-level component registered in route config | Both |
| Commerce SDK React hooks | Client-side SCAPI data fetching (useProduct, useBasket, etc.) | Client |
| withReactQuery (v3+) | React Query integration for data caching | Both |
PWA Kit renders React components on the server to produce initial HTML, which is sent to the browser. React then hydrates the HTML on the client -- attaching event listeners and initializing state so the app becomes fully interactive.
Key SSR constraints:
window, document, navigator, and other browser APIs are undefined during SSRuseEffect for any code that requires browser APIs (it only runs on the client)| Layer | Role | Data Fetching | Example |
|---|---|---|---|
| Page component | Route-level, registered in app/routes.jsx | getProps() for SSR data | ProductDetailPage |
| Container component | Orchestrates data flow, connects to Commerce SDK | Commerce SDK hooks | ProductListContainer |
| Presentational component | Pure UI rendering, receives props | None (props only) | ProductTile, PriceDisplay |
| Layout component | Persistent shell (header, footer) | Minimal or none | AppConfig |
| Path | Purpose |
|---|---|
| app/pages/ | Page components (route-level) |
| app/components/ | Shared/reusable components |
| app/components/_app-config/ | Application shell (layout wrapper) |
| app/routes.jsx | Route definitions mapping URLs to page components |
| app/ssr.js | SSR server entry point |
| config/default.js | Default runtime configuration (Commerce API, sites) |
| config/[env].js | Environment-specific overrides |
The @salesforce/commerce-sdk-react package provides hooks that wrap SCAPI calls with React Query for caching, loading states, and error handling.
| Hook Category | Examples | Purpose |
|---|---|---|
| Product hooks | useProduct, useProducts, useSearchProducts | Fetch product data |
| Basket hooks | useBasket, useShopperBasketsMutation | Cart operations |
| Customer hooks | useCustomer, useShopperLoginMutation | Auth and profile |
| Category hooks | useCategories, useCategory | Navigation and browse |
| Promotion hooks | usePromotions | Active promotions |
All hooks return { data, isLoading, error, isError } and support React Query options (staleTime, cacheTime, refetchOnWindowFocus, enabled). Mutation hooks return { mutate, mutateAsync, isLoading, error }.
PWA Kit uses react-router-dom. Routes are defined in app/routes.jsx and map URL patterns to page components.
| Router API | Purpose |
|---|---|
| <Link to="..."> | Declarative navigation (client-side) |
| useNavigate() | Programmatic navigation |
| useParams() | Access URL parameters |
| useLocation() | Current URL, search params |
| useSearchParams() | Read/write URL query parameters |
| State Type | Tool | Scope | Examples |
|---|---|---|---|
| Server/remote state | Commerce SDK hooks (React Query) | Cached, shared | Products, basket, customer |
| Global client state | React Context | App-wide | User session, locale, currency |
| Local component state | useState / useReducer | Single component | Form inputs, UI toggles, selections |
| URL state | useSearchParams | Shareable | Filters, pagination, sort order |
Avoid duplicating server state in client state -- let Commerce SDK hooks be the source of truth for remote data.
| Technique | React API | When to Use |
|---|---|---|
| Memoize expensive computations | useMemo | Filtering, sorting large lists |
| Stable callback references | useCallback | Functions passed as props to child components |
| Component memoization | React.memo | Prevent re-render when props unchanged |
| Code splitting | React.lazy + Suspense | Large components not needed on initial render |
| Deferred updates | useDeferredValue (React 18+) | Non-urgent UI updates |
Pattern: Page component with getProps
const ProductDetailPage = ({ product }) => {
return <div>{product.name}</div>;
};
ProductDetailPage.getProps = async ({ params, api }) => {
// Fetch live docs for Commerce SDK shopperProducts API
return { product };
};
export default ProductDetailPage;
Pattern: Commerce SDK hook usage
const { data, isLoading, error } = useProduct({
parameters: { id: productId }
});
// Fetch live docs for @salesforce/commerce-sdk-react hooks
Pattern: App shell layout
const AppConfig = ({ children }) => (
<Box>
<Header />
<Box as="main">{children}</Box>
<Footer />
</Box>
);
Pattern: SSR-safe browser API access
useEffect(() => {
// This only runs on the client, never during SSR
// Fetch live docs for useEffect SSR behavior
}, []);
getProps() for SEO-critical, initial page load data (runs on server)Promise.all() inside getProps() for parallel data fetchingchildren props over deep prop drillinguseMemo and stable callbacks with useCallbackwindow, document, or browser APIs during render -- use useEffectnull or fallback UI for client-only features during SSRw={['100%', '50%', '33%']})app/theme/ rather than inline stylesFetch the latest PWA Kit developer guide, Commerce SDK React documentation, and Retail React App source for exact hook signatures, route configuration, and getProps API before implementing.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.