[React] Composable component with Context

发布时间 2023-03-30 01:04:45作者: Zhentiw

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