ProductContextProvider
A React context for a product: wrap part of the page once, then read the product anywhere inside it without passing it down.
import { ProductContextProvider, useProductContext, ProductContext, ProductContextValue, ProductContextProviderProps } from '@salla.sa/twilight-theme-engine/contexts';In plain words
Passing product through five layers of components gets tedious. Wrap that part of the page once, <ProductContextProvider value={{ product }}>, and any component inside can call useProductContext() to get { product }.
Outside a provider it returns null, so components that use it must handle that.
Signature
interface ProductContextValue {
product: Product;
}
interface ProductContextProviderProps {
children: ReactNode;
value: ProductContextValue;
}
function ProductContextProvider(props: ProductContextProviderProps): React.ReactElement
function useProductContext(): ProductContextValue | null
const ProductContext: React.Context<ProductContextValue | null>Try it live
import {
ProductContextProvider,
useProductContext,
} from '@salla.sa/twilight-theme-engine/contexts';
import type { Product } from '@salla.sa/twilight-theme-engine/types';
function ProductTitle() {
const context = useProductContext(); // null without a provider above
return context ? <h3>{context.product.name}</h3> : null;
}
export function ProductTile({ product }: { product: Product }) {
return (
<ProductContextProvider value={{ product }}>
<ProductTitle />
</ProductContextProvider>
);
}
Example
import {
ProductContextProvider,
useProductContext,
} from '@salla.sa/twilight-theme-engine/contexts';
import type { Product } from '@salla.sa/twilight-theme-engine/types';
function TileTitle() {
const context = useProductContext();
return context ? <h3>{context.product.name}</h3> : null;
}
export function ProductTile({ product }: { product: Product }) {
return (
<ProductContextProvider value={{ product }}>
<TileTitle />
</ProductContextProvider>
);
}
How it behaves
It is a plain React context and nothing in the engine reads it: the engine's product page passes the product as props, and to hook slots through
HookSlot'scontextprop.The provider memoizes its value on
value.product, so consumers render again only when a different product object is passed.ProductContextitself is exported foruse(ProductContext)and class components.
Gotchas
The source comment says
HookSlotinjects this context intoproduct:*hook handlers. It does not:HookSlotbuilds the handler context from its owncontextprop andtwilightonly (src/hooks/HookSlot.tsx). Passcontext={{ product }}to the slot.
Related
Source and docs
- Engine source:
packages/theme-engine/src/contexts/ProductContext.tsx