[React] Composable component with Context
ProductCard component
import './ProductCard.css';
import { ReactNode } from 'react';
import * as React from 'react';
import ProductCardContext from './ProductCardContext';
import { Product } from '../types';
import ProductImage from './ProductImage';
import ProductButton from './ProductButton';
import ProductTitle from './ProductTitle';
import ProductInfo from './ProductInfo';
import ProductCategory from './ProductCategory';
import ProductRating from './ProductRating';
import ProductPrice from './ProductPrice';
type Props = {
product: Product;
image?: ReactNode;
info?: ReactNode;
action?: ReactNode;
};
function ProductCard({ image, info, action, product }: Props) {
return (
<ProductCardContext.Provider value={{ product }}>
<div className="product-card">
{image}
<div className="product-card-bottom">
{info}
{action}
</div>
</div>
</ProductCardContext.Provider>
);
}
ProductCard.Image = ProductImage;
ProductCard.Button = ProductButton;
ProductCard.Title = ProductTitle;
ProductCard.Info = ProductInfo;
ProductCard.Category = ProductCategory;
ProductCard.Rating = ProductRating;
ProductCard.Price = ProductPrice;
export default ProductCard;
Usage:
function App() {
const { addToCart } = useProduct(product);
return (
<ProductCard
product={product}
image={<ProductCard.Image />}
info={
<ProductCard.Info>
<ProductCard.Category />
<ProductCard.Title />
<ProductCard.Rating />
<ProductCard.Price />
</ProductCard.Info>
}
action={
<ProductCard.Button onClick={addToCart}>Add to cart</ProductCard.Button>
}
/>
);
}
Using context inside each compound component:
import * as React from 'react';
import { AiFillStar, AiOutlineStar } from 'react-icons/ai';
import { useProductCardContext } from './ProductCardContext';
function ProductRating() {
const { product } = useProductCardContext();
return (
<div className="product-rating">
{[1, 2, 3, 4, 5].map((i) =>
i <= product.rating.stars ? (
<AiFillStar key={i} />
) : (
<AiOutlineStar key={i} />
)
)}
</div>
);
}
export default ProductRating;
FullCode: https://stackblitz.com/edit/react-ts-uzanui?file=App.tsx
Video: https://www.youtube.com/watch?v=vPRdY87_SH0&list=WL&index=42&t=29s