Context
The payment_gateways, payment_methods, payment_source folders, and the order checkout flow components currently follow the container pattern: a *Container component owns state and provides it via context, while inner components consume that context.
This is the same pattern already refactored for address components (see standalone address forms). The goal is to apply the same approach here.
Current structure
payment_methods/
PaymentMethodsContainer.tsx ← owns state, provides PaymentMethodContext
PaymentMethod.tsx / PaymentMethodName.tsx / PaymentMethodPrice.tsx
payment_gateways/
PaymentGateway.tsx ← gateway dispatcher, reads PaymentMethodContext
AdyenGateway.tsx / BraintreeGateway.tsx / CheckoutComGateway.tsx / ...
payment_source/
PaymentSource.tsx ← reads PaymentMethodChildrenContext
AdyenPayment.tsx / BraintreePayment.tsx / CheckoutComPayment.tsx / ...
orders/
PlaceOrderContainer.tsx ← owns place-order state, provides PlaceOrderContext
PlaceOrderButton.tsx ← reads PlaceOrderContext
PrivacyAndTermsCheckbox.tsx ← reads PlaceOrderContext
Goal
Refactor following the same pattern used for standalone address components:
- Extract data-fetching and business logic into core functions and/or hooks (e.g.
usePaymentMethods, usePlaceOrder)
- Each component becomes self-contained — it accepts props directly and does not require a wrapping
*Container to work
- Deprecate container-pattern components with a JSDoc
@deprecated notice pointing to the new API
- Keep deprecated containers in this release for backwards compatibility
Implementation plan
Phase 1 — PaymentMethod (completed ✅)
- Created
usePlaceOrder hook encapsulating place-order state
PaymentMethod is now standalone (no PaymentMethodsContainer required)
Phase 2 — PlaceOrderButton, PlaceOrderContainer, PrivacyAndTermsCheckbox (completed ✅)
- Created
usePlaceOrder hook encapsulating place-order state
PlaceOrderButton is now standalone (accepts options prop directly)
PrivacyAndTermsCheckbox dispatches a DOM event (cl:placeorder:recheck) for sibling communication
- Deprecated
PlaceOrderContainer with @deprecated JSDoc
- 100% test coverage for all new code
Phase 3 — Payment gateways/source (upcoming)
- Extract
usePaymentMethods / usePaymentSource hooks
- Refactor each gateway and payment-source component
- Deprecate
PaymentMethodsContainer
References
- Pattern already applied to: address standalone forms (
AddressForm, BillingAddressForm, ShippingAddressForm)
- Related infinite re-render fixes — some were caused by the container anti-pattern itself
Context
The
payment_gateways,payment_methods,payment_sourcefolders, and the order checkout flow components currently follow the container pattern: a*Containercomponent owns state and provides it via context, while inner components consume that context.This is the same pattern already refactored for address components (see standalone address forms). The goal is to apply the same approach here.
Current structure
Goal
Refactor following the same pattern used for standalone address components:
usePaymentMethods,usePlaceOrder)*Containerto work@deprecatednotice pointing to the new APIImplementation plan
Phase 1 — PaymentMethod (completed ✅)
usePlaceOrderhook encapsulating place-order statePaymentMethodis now standalone (noPaymentMethodsContainerrequired)Phase 2 — PlaceOrderButton, PlaceOrderContainer, PrivacyAndTermsCheckbox (completed ✅)
usePlaceOrderhook encapsulating place-order statePlaceOrderButtonis now standalone (acceptsoptionsprop directly)PrivacyAndTermsCheckboxdispatches a DOM event (cl:placeorder:recheck) for sibling communicationPlaceOrderContainerwith@deprecatedJSDocPhase 3 — Payment gateways/source (upcoming)
usePaymentMethods/usePaymentSourcehooksPaymentMethodsContainerReferences
AddressForm,BillingAddressForm,ShippingAddressForm)