Podemos definir un patrón como una técnica que nos permite llegar a la resolución de problemas de distinta índole, como por ejemplo, problemas de comportamiento, estructurales, creacionales, entre otros.
En este caso, el patrón de composición de componentes o Compound Component Pattern aplicado a React, nos permite manejar la información desde un componente padre y tener control total de todos los componentes hijos.
<ProductCard product={product} className="bg-dark">
<ProductImage />
<ProductTitle />
<ProductButtons />
</ProductCard>
En este caso tenemos el componente ProductCard, el cual recibe como children 3 componentes los cuales también reciben información desde el padre a través del React Context, a continuación los veremos a detalle
ProductCard
import React, {
createContext,
ReactElement,
} from "react";
import styles from "../styles/styles.module.css";
import useProduct from "../hooks/useProduct";
import { Product, ProductContextProps } from "../interfaces";
import { ProductImage } from "./ProductImage";
import { ProductTitle } from "./ProductTitle";
import { ProductButtons } from "./ProductButtons";
export const ProductContext = createContext({} as ProductContextProps);
const { Provider } = ProductContext;
interface Props {
product: Product;
children: ReactElement | Array<ReactElement>;
className: string;
}
const ProductCard = ({ children, product, className }: Props) => {
const { counter, increaseBy } = useProduct();
return (
<Provider
value={{
counter,
increaseBy,
product,
className
}}
>
<div className={styles.productCard}>
{children}
</div>
</Provider>
);
};
export default ProductCard;
ProductImage
import { useContext } from "react";
import { ProductContext } from "./ProductCard";
import noImage from "../assets/no-image.jpg";
import styles from "../styles/styles.module.css";
export const ProductImage = ({ img = "" }) => {
const { product } = useContext(ProductContext);
let imgToShow: string;
if(img) {
imgToShow = img;
} else if(product.img) {
imgToShow = product.img
} else {
imgToShow = noImage
}
return (
<img
className={styles.productImg}
src={imgToShow}
alt="Coffee Mug"
/>
);
};
ProductTitle
import { useContext } from "react";
import { ProductContext } from "./ProductCard";
import styles from "../styles/styles.module.css";
export const ProductTitle = ({ title }: { title?: string }) => {
const { product } = useContext(ProductContext);
return (
<span className={styles.productDescription}>
{title ? title : product.title}
</span>
);
};
ProductButtons
import { useContext } from "react";
import { ProductContext } from "./ProductCard";
import styles from "../styles/styles.module.css";
export const ProductButtons = () => {
const { increaseBy, counter } = useContext(ProductContext);
return (
<div className={styles.buttonsContainer}>
<button className={styles.buttonMinus} onClick={() => increaseBy(-1)}>
-
</button>
<div className={styles.countLabel}>{counter}</div>
<button className={styles.buttonAdd} onClick={() => increaseBy(+1)}>
+
</button>
</div>
);
};
Como podemos ver, cada componente hijo recibe diferentes Props como counter, increaseBy, product y className, sin embargo a través del React Context, tenemos el control total desde nuestro componente padre. Esto nos abre una gran variedad de posibilidades para construir componentes reutilizables e incluso librerías personalizadas. Finalmente, aclarar que la meta principal de este patrón es lograr que nuestro componente sea lo más flexible posible.
Top comments (0)