faststore-state-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

FastStore SDK State Management

FastStore SDK 状态管理

When this skill applies

本技能的适用场景

Use this skill when:
  • You are building any interactive ecommerce feature that involves the shopping cart, user session, product search/filtering, or analytics tracking.
  • You need to add, remove, or update cart items.
  • You need to read or change session data (currency, locale, sales channel, postal code).
  • You need to manage faceted search state (sort order, selected facets, pagination).
  • You are working with
    @faststore/sdk
    hooks (
    useCart
    ,
    useSession
    ,
    useSearch
    ).
Do not use this skill for:
  • Visual-only changes — use the
    faststore-theming
    skill.
  • Replacing or customizing native components — use the
    faststore-overrides
    skill.
  • Extending the GraphQL schema or fetching custom data — use the
    faststore-data-fetching
    skill.
在以下场景中使用本技能:
  • 你正在构建涉及购物车、用户会话、产品搜索/筛选或分析追踪的交互式电商功能。
  • 你需要添加、删除或更新购物车商品。
  • 你需要读取或修改会话数据(货币、区域设置、销售渠道、邮政编码)。
  • 你需要管理分面搜索状态(排序方式、已选筛选条件、分页)。
  • 你正在使用
    @faststore/sdk
    的Hook(
    useCart
    useSession
    useSearch
    )。
请勿在以下场景中使用本技能:
  • 仅视觉层面的修改——请使用
    faststore-theming
    技能。
  • 替换或自定义原生组件——请使用
    faststore-overrides
    技能。
  • 扩展GraphQL Schema或获取自定义数据——请使用
    faststore-data-fetching
    技能。

Decision rules

决策规则

  • Use
    useCart()
    for all cart operations — it handles platform validation, price verification, and analytics automatically.
  • Use
    useSession()
    for all session data — it triggers
    validateSession
    mutations that keep the platform synchronized.
  • Use
    useSearch()
    within
    SearchProvider
    for all search state — it synchronizes with URL parameters and supports browser back-button navigation.
  • Do not build custom state management (React Context, Redux, Zustand,
    useState
    /
    useReducer
    ) for cart, session, or search. The SDK hooks are wired into the FastStore platform integration layer.
  • Always check
    isValidating
    from
    useCart()
    and block checkout navigation during validation.
  • Use
    sendAnalyticsEvent()
    from the SDK for GA4-compatible ecommerce event tracking.
  • 所有购物车操作均使用
    useCart()
    ——它会自动处理平台验证、价格校验和分析事件。
  • 所有会话数据均使用
    useSession()
    ——它会触发
    validateSession
    变更操作,保持与平台的同步。
  • 所有搜索状态均在
    SearchProvider
    中使用
    useSearch()
    ——它会与URL参数同步,并支持浏览器后退按钮导航。
  • 请勿为购物车、会话或搜索构建自定义状态管理(React Context、Redux、Zustand、
    useState
    /
    useReducer
    )。SDK的Hook已与FastStore平台集成层关联。
  • 务必检查
    useCart()
    返回的
    isValidating
    状态,并在验证期间阻止结账导航。
  • 使用SDK中的
    sendAnalyticsEvent()
    来实现兼容GA4的电商事件追踪。

Hard constraints

硬性约束

Constraint: Use @faststore/sdk for Cart, Session, and Search State

约束:使用@faststore/sdk管理购物车、会话和搜索状态

MUST use
@faststore/sdk
hooks (
useCart
,
useSession
,
useSearch
) for managing cart, session, and search state. MUST NOT build custom state management (React Context, Redux, Zustand, useState/useReducer) for these domains.
Why this matters The SDK hooks are wired into the FastStore platform integration layer.
useCart()
triggers cart validation mutations.
useSession()
propagates locale/currency changes to all data queries.
useSearch()
synchronizes with URL parameters and triggers search re-fetches. Custom state bypasses all of this — carts won't be validated, prices may be stale, search won't sync with URLs, and analytics events won't fire.
Detection If you see
useState
or
useReducer
managing cart items, cart totals, session locale, session currency, or search facets → STOP. These should use
useCart()
,
useSession()
, or
useSearch()
from
@faststore/sdk
. If you see
createContext
with names like
CartContext
,
SessionContext
, or
SearchContext
→ STOP. The SDK already provides these contexts.
Correct
typescript
// src/components/MiniCart.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function MiniCart() {
  const { items, totalItems, isValidating, removeItem } = useCart()

  if (totalItems === 0) {
    return <p>Your cart is empty</p>
  }

  return (
    <div data-fs-mini-cart>
      <h3>Cart ({totalItems} items)</h3>
      {isValidating && <span>Updating cart...</span>}
      <ul>
        {items.map((item) => (
          <li key={item.id}>
            <span>{item.itemOffered.name}</span>
            <span>${item.price}</span>
            <button onClick={() => removeItem(item.id)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  )
}
Wrong
typescript
// WRONG: Building a custom cart context instead of using @faststore/sdk
import React, { createContext, useContext, useReducer } from 'react'

interface CartItem {
  id: string
  name: string
  price: number
  quantity: number
}

// This custom context duplicates what @faststore/sdk already provides.
// Cart changes here will NOT trigger platform validation.
// Prices and availability will NOT be verified against VTEX.
// Analytics events will NOT fire for add-to-cart actions.
const CartContext = createContext<{
  items: CartItem[]
  dispatch: React.Dispatch<any>
}>({ items: [], dispatch: () => {} })

function cartReducer(state: CartItem[], action: any) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.payload]
    case 'REMOVE':
      return state.filter((item) => item.id !== action.payload)
    default:
      return state
  }
}

export function CartProvider({ children }: { children: React.ReactNode }) {
  const [items, dispatch] = useReducer(cartReducer, [])
  return (
    <CartContext.Provider value={{ items, dispatch }}>
      {children}
    </CartContext.Provider>
  )
}

必须使用
@faststore/sdk
的Hook(
useCart
useSession
useSearch
)来管理购物车、会话和搜索状态。严禁为这些领域构建自定义状态管理(React Context、Redux、Zustand、useState/useReducer)。
重要性说明 SDK的Hook已与FastStore平台集成层关联。
useCart()
会触发购物车验证变更操作。
useSession()
会将区域设置/货币变更同步到所有数据查询。
useSearch()
会与URL参数同步,并触发搜索重获取。自定义状态会绕过所有这些机制——购物车不会被验证,价格可能过时,搜索无法与URL同步,分析事件也不会触发。
检测方式 如果你看到
useState
useReducer
在管理购物车商品、购物车总额、会话区域设置、会话货币或搜索筛选条件→立即停止。这些场景应使用
@faststore/sdk
提供的
useCart()
useSession()
useSearch()
。如果你看到名为
CartContext
SessionContext
SearchContext
createContext
→立即停止。SDK已提供这些上下文。
正确示例
typescript
// src/components/MiniCart.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function MiniCart() {
  const { items, totalItems, isValidating, removeItem } = useCart()

  if (totalItems === 0) {
    return <p>Your cart is empty</p>
  }

  return (
    <div data-fs-mini-cart>
      <h3>Cart ({totalItems} items)</h3>
      {isValidating && <span>Updating cart...</span>}
      <ul>
        {items.map((item) => (
          <li key={item.id}>
            <span>{item.itemOffered.name}</span>
            <span>${item.price}</span>
            <button onClick={() => removeItem(item.id)}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  )
}
错误示例
typescript
// WRONG: Building a custom cart context instead of using @faststore/sdk
import React, { createContext, useContext, useReducer } from 'react'

interface CartItem {
  id: string
  name: string
  price: number
  quantity: number
}

// This custom context duplicates what @faststore/sdk already provides.
// Cart changes here will NOT trigger platform validation.
// Prices and availability will NOT be verified against VTEX.
// Analytics events will NOT fire for add-to-cart actions.
const CartContext = createContext<{
  items: CartItem[]
  dispatch: React.Dispatch<any>
}>({ items: [], dispatch: () => {} })

function cartReducer(state: CartItem[], action: any) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.payload]
    case 'REMOVE':
      return state.filter((item) => item.id !== action.payload)
    default:
      return state
  }
}

export function CartProvider({ children }: { children: React.ReactNode }) {
  const [items, dispatch] = useReducer(cartReducer, [])
  return (
    <CartContext.Provider value={{ items, dispatch }}>
      {children}
    </CartContext.Provider>
  )
}

Constraint: Always Handle Cart Validation State

约束:务必处理购物车验证状态

MUST check the
isValidating
flag from
useCart()
and show appropriate loading states during cart validation. MUST NOT allow checkout navigation while
isValidating
is
true
.
Why this matters Cart validation is an asynchronous operation that checks items against the VTEX platform for current prices, availability, and applicable promotions. If a user proceeds to checkout during validation, they may see stale prices or encounter errors. The
isValidating
flag exists to prevent this.
Detection If you see
useCart()
destructured without
isValidating
in components that have checkout links or "Proceed to Checkout" buttons → warn that the validation state is not being handled. If you see a checkout link or button that does not check
isValidating
before navigating → warn about potential stale cart data.
Correct
typescript
// src/components/CartSummary.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function CartSummary() {
  const { items, totalItems, isValidating } = useCart()

  const subtotal = items.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  )

  return (
    <div data-fs-cart-summary>
      <p>{totalItems} item{totalItems !== 1 ? 's' : ''} in your cart</p>
      <p>Subtotal: ${subtotal.toFixed(2)}</p>
      {isValidating && (
        <p data-fs-cart-validating>Verifying prices and availability...</p>
      )}
      <a
        href="/checkout"
        data-fs-checkout-button
        aria-disabled={isValidating}
        onClick={(e) => {
          if (isValidating) {
            e.preventDefault()
          }
        }}
      >
        {isValidating ? 'Updating cart...' : 'Proceed to Checkout'}
      </a>
    </div>
  )
}
Wrong
typescript
// WRONG: Ignoring cart validation state
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function CartSummary() {
  const { items, totalItems } = useCart()
  // Missing isValidating — user can click checkout while cart is being validated.
  // This can lead to price mismatches at checkout or failed orders.

  return (
    <div>
      <p>{totalItems} items</p>
      <a href="/checkout">Proceed to Checkout</a>
      {/* No loading state. No validation check. User may proceed with stale prices. */}
    </div>
  )
}

必须检查
useCart()
返回的
isValidating
标志,并在购物车验证期间显示合适的加载状态。当
isValidating
true
时,严禁允许结账导航。
重要性说明 购物车验证是一个异步操作,会对照VTEX平台检查商品的当前价格、库存和适用促销活动。如果用户在验证期间进入结账流程,可能会看到过时的价格或遇到错误。
isValidating
标志就是为了防止这种情况而设置的。
检测方式 如果你看到在包含结账链接或“前往结账”按钮的组件中,解构
useCart()
时没有获取
isValidating
→警告未处理验证状态。如果你看到结账链接或按钮在导航前未检查
isValidating
→警告可能存在过时购物车数据的风险。
正确示例
typescript
// src/components/CartSummary.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function CartSummary() {
  const { items, totalItems, isValidating } = useCart()

  const subtotal = items.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  )

  return (
    <div data-fs-cart-summary>
      <p>{totalItems} item{totalItems !== 1 ? 's' : ''} in your cart</p>
      <p>Subtotal: ${subtotal.toFixed(2)}</p>
      {isValidating && (
        <p data-fs-cart-validating>Verifying prices and availability...</p>
      )}
      <a
        href="/checkout"
        data-fs-checkout-button
        aria-disabled={isValidating}
        onClick={(e) => {
          if (isValidating) {
            e.preventDefault()
          }
        }}
      >
        {isValidating ? 'Updating cart...' : 'Proceed to Checkout'}
      </a>
    </div>
  )
}
错误示例
typescript
// WRONG: Ignoring cart validation state
import React from 'react'
import { useCart } from '@faststore/sdk'

export default function CartSummary() {
  const { items, totalItems } = useCart()
  // Missing isValidating — user can click checkout while cart is being validated.
  // This can lead to price mismatches at checkout or failed orders.

  return (
    <div>
      <p>{totalItems} items</p>
      <a href="/checkout">Proceed to Checkout</a>
      {/* No loading state. No validation check. User may proceed with stale prices. */}
    </div>
  )
}

Constraint: Do Not Store Session Data in localStorage

约束:请勿将会话数据存储在localStorage中

MUST use
useSession()
from
@faststore/sdk
for accessing session data (currency, locale, channel, person). MUST NOT read/write session data directly to
localStorage
or
sessionStorage
.
Why this matters The SDK's session module manages synchronization with the VTEX platform. When session data changes, the SDK triggers a
validateSession
mutation that updates the server-side session and re-validates the cart. Writing directly to
localStorage
bypasses this validation — the platform won't know about the change, prices may display in the wrong currency, and cart items may not reflect the correct sales channel.
Detection If you see
localStorage.getItem
or
localStorage.setItem
with keys related to session data (currency, locale, channel, region, postalCode) → STOP. These should be managed through
useSession()
. If you see
sessionStorage
used for the same purpose → STOP.
Correct
typescript
// src/components/LocaleSwitcher.tsx
import React from 'react'
import { useSession } from '@faststore/sdk'

export default function LocaleSwitcher() {
  const { locale, currency, setSession } = useSession()

  const handleLocaleChange = (newLocale: string, newCurrency: string) => {
    // setSession triggers platform validation and re-fetches data
    setSession({
      locale: newLocale,
      currency: { code: newCurrency, symbol: newCurrency === 'USD' ? '$' : 'R$' },
    })
  }

  return (
    <div data-fs-locale-switcher>
      <button
        onClick={() => handleLocaleChange('en-US', 'USD')}
        aria-pressed={locale === 'en-US'}
      >
        EN
      </button>
      <button
        onClick={() => handleLocaleChange('pt-BR', 'BRL')}
        aria-pressed={locale === 'pt-BR'}
      >
        PT
      </button>
      <span>Current: {locale} ({currency.code})</span>
    </div>
  )
}
Wrong
typescript
// WRONG: Managing session data manually via localStorage
import React, { useState, useEffect } from 'react'

export default function LocaleSwitcher() {
  const [locale, setLocale] = useState('en-US')

  useEffect(() => {
    // WRONG: Reading session data from localStorage
    const saved = localStorage.getItem('store-locale')
    if (saved) setLocale(saved)
  }, [])

  const handleLocaleChange = (newLocale: string) => {
    // WRONG: Writing session data to localStorage
    // The VTEX platform does NOT know about this change.
    // Product prices, availability, and cart will NOT update.
    localStorage.setItem('store-locale', newLocale)
    setLocale(newLocale)
  }

  return (
    <div>
      <button onClick={() => handleLocaleChange('en-US')}>EN</button>
      <button onClick={() => handleLocaleChange('pt-BR')}>PT</button>
    </div>
  )
}
必须使用
@faststore/sdk
useSession()
来访问会话数据(货币、区域设置、渠道、用户信息)。严禁直接读写
localStorage
sessionStorage
来处理会话数据。
重要性说明 SDK的会话模块负责与VTEX平台保持同步。当会话数据变更时,SDK会触发
validateSession
变更操作,更新服务器端会话并重新验证购物车。直接写入
localStorage
会绕过该验证流程——平台不会知晓变更,价格可能会以错误的货币显示,购物车商品也可能无法反映正确的销售渠道。
检测方式 如果你看到
localStorage.getItem
localStorage.setItem
用于会话相关数据(货币、区域设置、渠道、地区、邮政编码)→立即停止。这些数据应通过
useSession()
管理。如果你看到
sessionStorage
被用于相同目的→立即停止。
正确示例
typescript
// src/components/LocaleSwitcher.tsx
import React from 'react'
import { useSession } from '@faststore/sdk'

export default function LocaleSwitcher() {
  const { locale, currency, setSession } = useSession()

  const handleLocaleChange = (newLocale: string, newCurrency: string) => {
    // setSession triggers platform validation and re-fetches data
    setSession({
      locale: newLocale,
      currency: { code: newCurrency, symbol: newCurrency === 'USD' ? '$' : 'R$' },
    })
  }

  return (
    <div data-fs-locale-switcher>
      <button
        onClick={() => handleLocaleChange('en-US', 'USD')}
        aria-pressed={locale === 'en-US'}
      >
        EN
      </button>
      <button
        onClick={() => handleLocaleChange('pt-BR', 'BRL')}
        aria-pressed={locale === 'pt-BR'}
      >
        PT
      </button>
      <span>Current: {locale} ({currency.code})</span>
    </div>
  )
}
错误示例
typescript
// WRONG: Managing session data manually via localStorage
import React, { useState, useEffect } from 'react'

export default function LocaleSwitcher() {
  const [locale, setLocale] = useState('en-US')

  useEffect(() => {
    // WRONG: Reading session data from localStorage
    const saved = localStorage.getItem('store-locale')
    if (saved) setLocale(saved)
  }, [])

  const handleLocaleChange = (newLocale: string) => {
    // WRONG: Writing session data to localStorage
    // The VTEX platform does NOT know about this change.
    // Product prices, availability, and cart will NOT update.
    localStorage.setItem('store-locale', newLocale)
    setLocale(newLocale)
  }

  return (
    <div>
      <button onClick={() => handleLocaleChange('en-US')}>EN</button>
      <button onClick={() => handleLocaleChange('pt-BR')}>PT</button>
    </div>
  )
}

Preferred pattern

推荐模式

Recommended usage of SDK hooks together:
typescript
// src/components/CartDrawer.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'
import { useSession } from '@faststore/sdk'
import { Button, Loader } from '@faststore/ui'

export default function CartDrawer() {
  const { items, totalItems, isValidating, removeItem, updateItemQuantity } =
    useCart()
  const { currency, locale } = useSession()

  const formatter = new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency.code,
  })

  const subtotal = items.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  )

  if (totalItems === 0) {
    return (
      <div data-fs-cart-drawer>
        <h2>Your Cart</h2>
        <p>Your cart is empty. Start shopping to add items.</p>
      </div>
    )
  }

  return (
    <div data-fs-cart-drawer>
      <h2>Your Cart ({totalItems} items)</h2>

      {isValidating && (
        <div data-fs-cart-loading>
          <Loader />
          <span>Verifying prices and availability...</span>
        </div>
      )}

      <ul data-fs-cart-items>
        {items.map((item) => (
          <li key={item.id} data-fs-cart-item>
            <span data-fs-cart-item-name>{item.itemOffered.name}</span>
            <span data-fs-cart-item-price>{formatter.format(item.price)}</span>
            <div data-fs-cart-item-quantity>
              <Button
                variant="tertiary"
                onClick={() => updateItemQuantity(item.id, item.quantity - 1)}
                disabled={item.quantity <= 1}
              >
                -
              </Button>
              <span>{item.quantity}</span>
              <Button
                variant="tertiary"
                onClick={() => updateItemQuantity(item.id, item.quantity + 1)}
              >
                +
              </Button>
            </div>
            <Button variant="tertiary" onClick={() => removeItem(item.id)}>
              Remove
            </Button>
          </li>
        ))}
      </ul>

      <div data-fs-cart-summary>
        <span>Subtotal: {formatter.format(subtotal)}</span>
        <a
          href="/checkout"
          data-fs-checkout-button
          aria-disabled={isValidating}
          onClick={(e) => {
            if (isValidating) e.preventDefault()
          }}
        >
          {isValidating ? 'Updating cart...' : 'Proceed to Checkout'}
        </a>
      </div>
    </div>
  )
}
Search state with
useSearch()
:
typescript
// src/components/FacetFilter.tsx
import { useSearch } from '@faststore/sdk'

export default function FacetFilter() {
  const { state, setState } = useSearch()

  const toggleFacet = (facetKey: string, facetValue: string) => {
    const currentFacets = state.selectedFacets || []
    const exists = currentFacets.some(
      (f) => f.key === facetKey && f.value === facetValue
    )

    const newFacets = exists
      ? currentFacets.filter(
          (f) => !(f.key === facetKey && f.value === facetValue)
        )
      : [...currentFacets, { key: facetKey, value: facetValue }]

    setState({
      ...state,
      selectedFacets: newFacets,
      page: 0, // Reset pagination when filters change
    })
  }

  return (
    <div data-fs-facet-filter>
      <button onClick={() => toggleFacet('brand', 'Nike')}>
        Nike {state.selectedFacets?.some((f) => f.key === 'brand' && f.value === 'Nike') ? '✓' : ''}
      </button>
    </div>
  )
}
SDK Hook的组合使用推荐:
typescript
// src/components/CartDrawer.tsx
import React from 'react'
import { useCart } from '@faststore/sdk'
import { useSession } from '@faststore/sdk'
import { Button, Loader } from '@faststore/ui'

export default function CartDrawer() {
  const { items, totalItems, isValidating, removeItem, updateItemQuantity } =
    useCart()
  const { currency, locale } = useSession()

  const formatter = new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency.code,
  })

  const subtotal = items.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  )

  if (totalItems === 0) {
    return (
      <div data-fs-cart-drawer>
        <h2>Your Cart</h2>
        <p>Your cart is empty. Start shopping to add items.</p>
      </div>
    )
  }

  return (
    <div data-fs-cart-drawer>
      <h2>Your Cart ({totalItems} items)</h2>

      {isValidating && (
        <div data-fs-cart-loading>
          <Loader />
          <span>Verifying prices and availability...</span>
        </div>
      )}

      <ul data-fs-cart-items>
        {items.map((item) => (
          <li key={item.id} data-fs-cart-item>
            <span data-fs-cart-item-name>{item.itemOffered.name}</span>
            <span data-fs-cart-item-price>{formatter.format(item.price)}</span>
            <div data-fs-cart-item-quantity>
              <Button
                variant="tertiary"
                onClick={() => updateItemQuantity(item.id, item.quantity - 1)}
                disabled={item.quantity <= 1}
              >
                -
              </Button>
              <span>{item.quantity}</span>
              <Button
                variant="tertiary"
                onClick={() => updateItemQuantity(item.id, item.quantity + 1)}
              >
                +
              </Button>
            </div>
            <Button variant="tertiary" onClick={() => removeItem(item.id)}>
              Remove
            </Button>
          </li>
        ))}
      </ul>

      <div data-fs-cart-summary>
        <span>Subtotal: {formatter.format(subtotal)}</span>
        <a
          href="/checkout"
          data-fs-checkout-button
          aria-disabled={isValidating}
          onClick={(e) => {
            if (isValidating) e.preventDefault()
          }}
        >
          {isValidating ? 'Updating cart...' : 'Proceed to Checkout'}
        </a>
      </div>
    </div>
  )
}
使用
useSearch()
管理搜索状态:
typescript
// src/components/FacetFilter.tsx
import { useSearch } from '@faststore/sdk'

export default function FacetFilter() {
  const { state, setState } = useSearch()

  const toggleFacet = (facetKey: string, facetValue: string) => {
    const currentFacets = state.selectedFacets || []
    const exists = currentFacets.some(
      (f) => f.key === facetKey && f.value === facetValue
    )

    const newFacets = exists
      ? currentFacets.filter(
          (f) => !(f.key === facetKey && f.value === facetValue)
        )
      : [...currentFacets, { key: facetKey, value: facetValue }]

    setState({
      ...state,
      selectedFacets: newFacets,
      page: 0, // Reset pagination when filters change
    })
  }

  return (
    <div data-fs-facet-filter>
      <button onClick={() => toggleFacet('brand', 'Nike')}>
        Nike {state.selectedFacets?.some((f) => f.key === 'brand' && f.value === 'Nike') ? '✓' : ''}
      </button>
    </div>
  )
}

Common failure modes

常见错误模式

  • Creating a custom React Context for cart state (
    CartContext
    ,
    useReducer
    ) — disconnects from VTEX platform validation, analytics, and checkout.
  • Storing session data (locale, currency, postal code) in
    localStorage
    — the SDK's
    validateSession
    mutation never fires, so the platform is out of sync.
  • Building custom search state with
    useState
    — loses URL synchronization, breaks back-button navigation, and bypasses the SDK's optimized query generation.
  • Ignoring the
    isValidating
    flag from
    useCart()
    — users can proceed to checkout with stale prices or out-of-stock items.
  • Using
    useCart_unstable
    or
    useSession_unstable
    hooks without understanding they have unstable interfaces that may change.
  • 为购物车状态创建自定义React Context(
    CartContext
    useReducer
    )——断开与VTEX平台验证、分析和结账流程的连接。
  • 将会话数据(区域设置、货币、邮政编码)存储在
    localStorage
    中——SDK的
    validateSession
    变更操作永远不会触发,导致平台数据不同步。
  • 使用
    useState
    构建自定义搜索状态——失去URL同步功能,破坏后退按钮导航,绕过SDK的优化查询生成机制。
  • 忽略
    useCart()
    返回的
    isValidating
    标志——用户可能带着过时的价格或缺货商品进入结账流程。
  • 在未理解其不稳定接口可能发生变更的情况下,使用
    useCart_unstable
    useSession_unstable
    Hook。

Review checklist

审核清单

  • Is cart state managed exclusively via
    useCart()
    from
    @faststore/sdk
    ?
  • Is session data accessed exclusively via
    useSession()
    from
    @faststore/sdk
    ?
  • Is search state managed via
    useSearch()
    within a
    SearchProvider
    context?
  • Is the
    isValidating
    flag checked before allowing checkout navigation?
  • Is there no custom React Context, Redux, or Zustand store duplicating SDK state?
  • Is there no direct
    localStorage
    /
    sessionStorage
    access for session-related data?
  • 购物车状态是否完全通过
    @faststore/sdk
    useCart()
    管理?
  • 会话数据是否完全通过
    @faststore/sdk
    useSession()
    访问?
  • 搜索状态是否在
    SearchProvider
    上下文中通过
    useSearch()
    管理?
  • 在允许结账导航前是否检查了
    isValidating
    标志?
  • 是否没有自定义React Context、Redux或Zustand存储来复现SDK的状态管理功能?
  • 是否没有直接通过
    localStorage
    /
    sessionStorage
    访问会话相关数据?

Reference

参考资料

  • FastStore SDK overview — Introduction to the SDK modules and their responsibilities
  • useCart hook — API reference for the cart hook with all properties and functions
  • Cart module overview — Cart data structure, validation, and platform integration
  • Session module — Session data structure, currency, locale, and channel management
  • useSearch hook — API reference for the search hook with sorting, facets, and pagination
  • SearchProvider — Context provider required for useSearch to function
  • Analytics module — GA4-compatible analytics event tracking
  • Experimental hooks and components — Unstable hooks for advanced use cases (useCart_unstable, useSession_unstable)
  • faststore-data-fetching
    — Related skill for fetching product data via the GraphQL API
  • FastStore SDK 概述——SDK模块及其职责的介绍
  • useCart Hook——购物车Hook的API参考,包含所有属性和函数
  • 购物车模块概述——购物车数据结构、验证和平台集成说明
  • 会话模块——会话数据结构、货币、区域设置和渠道管理说明
  • useSearch Hook——搜索Hook的API参考,包含排序、筛选和分页功能
  • SearchProvider——
    useSearch
    正常工作所需的上下文提供者
  • 分析模块——兼容GA4的分析事件追踪功能
  • 实验性Hook和组件——适用于高级场景的不稳定Hook(useCart_unstable、useSession_unstable)
  • faststore-data-fetching
    ——通过GraphQL API获取产品数据的相关技能