Skip to main content

sfnext-state-management

Manage client-side state in Storefront Next using React context providers and feature-level Zustand stores. Use when handling basket/auth UI state, creating extension stores (for example store locator), or syncing client-visible state after server mutations. NOT for server-side data loading — see sfnext-data-fetching for loader patterns.

Informações da origem

Repositório
SalesforceCommerceCloud/b2c-developer-tooling
Última atividade na origem
24 de abril de 2026 às 15:36
Idioma detectado do SKILL.md
inglês
Estrelas
54
Forks
21

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
sfnext-state-management
description
Manage client-side state in Storefront Next using React context providers and feature-level Zustand stores. Use when handling basket/auth UI state, creating extension stores (for example store locator), or syncing client-visible state after server mutations. NOT for server-side data loading — see sfnext-data-fetching for loader patterns.
# State Management Skill This skill covers client-side state management in Storefront Next with server-first data loading. ## Overview Storefront Next keeps business data on the server (`loader`/`action`) and uses client state for UX continuity. In practice, app-wide state is commonly exposed through providers (for example auth/basket), while complex extension-specific state can use Zustand. | State Type | Mechanism | Example | | --------------------- | ------------------------------ | ------------------------------------------------------ | | Server data | React Router `loader` | Product details, category listings | | App-wide client state | React context providers | Session display state, basket snapshot/hydration state | | Feature client state | Zustand store | Store locator modal/search state | | Mutations | React Router `action` (server) | Add to cart, update profile | ## Zustand Store Pattern (Feature-Level) ```typescript // src/extensions/store-locator/stores/store-locator-store.ts import {createStore} from 'zustand/vanilla'; type StoreLocatorState = { isOpen: boolean; mode: 'input' | 'device'; selectedStoreInfo: SelectedStoreInfo | null; }; type StoreLocatorActions = { open: () => void; close: () => void; setSelectedStoreInfo: (info: SelectedStoreInfo) => void; }; type StoreLocatorStore = StoreLocatorState & StoreLocatorActions; export const createStoreLocatorStore = (init?: Partial<StoreLocatorState>) => { return createStore<StoreLocatorStore>()((set) => ({ isOpen: false, mode: 'input', selectedStoreInfo: init?.selectedStoreInfo ?? null, open: () => set({isOpen: true}), close: () => set({isOpen: false}), setSelectedStoreInfo: (selectedStoreInfo) => set({selectedStoreInfo}), })); }; ``` ## Context Integration Expose app-level state to components via providers/hooks: ```typescript import { useBasket, useBasketSnapshot } from '@/providers/basket'; // In components function CartIcon() { const basket = useBasket(); const snapshot = useBasketSnapshot(); const itemCount = basket?.productItems?.length ?? snapshot?.uniqueProductCount ?? 0; return <Badge count={itemCount} />; } ``` ## Post-Mutation Sync Pattern Keep mutations on the server and update request-context resources there: ```typescript import {data} from 'react-router'; import {getBasket, updateBasketResource} from '@/middlewares/basket.server'; export async function action({request, context}: ActionFunctionArgs) { const formData = await request.formData(); const productId = formData.get('productId') as string; const basketResource = await getBasket(context); const clients = createApiClients(context); const {data: updatedBasket} = await clients.basket.addItemToBasket({ params: {path: {basketId: basketResource.current?.basketId ?? ''}}, body: {productId, quantity: 1}, }); // Sync basket resource in request context for current response/revalidation flow updateBasketResource(context, updatedBasket); return data({success: true, basket: updatedBasket}); } ``` ## Best Practices 1. **Server-first data** — Load/mutate commerce data with `loader`/`action` 2. **Provider-first app state** — Use providers for shared basket/auth UI state 3. **Scoped Zustand usage** — Use Zustand for feature-local complexity (typically extensions) 4. **Sync in server actions** — Update server basket/auth resources inside `action` handlers 5. **Keep state minimal** — Store only what cannot be derived cheaply ## When to Use Each Mechanism | Scenario | Use | | ----------------------------- | -------------------------------------------------------- | | Product data on page load | `loader` | | Shopping cart badge count | Basket provider hooks (`useBasket`, `useBasketSnapshot`) | | Complex extension UI workflow | Zustand store | | Search results | `loader` | | Add to cart | Server `action` + resource update | ## Related Skills - `storefront-next:sfnext-data-fetching` - Server-side data loading with loaders (NOT client state) - `storefront-next:sfnext-authentication` - Auth state management - `storefront-next:sfnext-components` - Using store data in components
Ver no GitHub