2. 상품 목록
// ProductListPage.tsx
export default function ProductListpage() {
const [params] = useSearchParams();
const categoryId = params.get("categoryId") ?? undefined;
const { products } = useFetchProducts({ categoryId });
return (
<div>
<h2>Products</h2>
<Products products={products} />
</div>
);
}
// Products.tsx
export default function Products({ products }: ProductsProps) {
if (!products.length) {
return null;
}
return (
<Container>
<ul>
{products.map((product) => (
<li key={product.id}>
<Link to={`/products/${product.id}`}>
<Product product={product} />
</Link>
</li>
))}
</ul>
</Container>
);
}
// Product.tsx
export default function Product({ product }: ProductProps) {
return (
<div>
<Thumbnail src={product.thumbnail.url} />
<div>{product.name}</div>
<div>{numberFormat(product.price)}원</div>
</div>
);
}
view를 보여주는 컴포넌트들을 만들었다.
중요한 건 이 컴포넌트들의 관심사가 아닌 비즈니스 로직, 그러니까
데이터를 불러오는 일은 useFetchProducts
라는 훅에 의해 일어난다.
컴포넌트에서 선언적으로 훅을 이용해 데이터를 얻어다 쓰기만 하는 것.
const apiBaseUrl = "https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
export default function useFetchProducts() {
type Data = {
products: ProductSummary[],
};
const { data } = useFetch < Data > `${apiBaseUrl}/products`;
return {
products: data?.products ?? [],
};
}
ProductsStore.ts
상품 목록을 Store로 관리할 수 있다.
@singleton()
@Store()
export default class ProductsStore {
products: ProductSummary[] = [];
async fetchProducts() {
this.setProducts([]);
const { data } = await axios.get(`${apiBaseUrl}/products`);
const { products } = data;
this.setProducts(products);
}
@Action()
setProducts(products: ProductSummary[]) {
this.products = products;
}
}
혹도 변경한다
export default function useFetchProducts(): {
products: ProductSummary[],
} {
const store = container.resolve(ProductsStore);
const [{ products }] = useStore(store);
useEffectOnce(() => {
store.fetchProducts();
});
return { products };
}
useStore는 data, store가 든 배열을 반환하는 usestore-ts 훅이다.
hook은 api 서버가 어딨는지, url이 뭔지 알 필요가 없기 때문에 그 부분은 store로 옮긴 것.
hook은 데이터를 store에서 가져와 return 해주는 데에만 관심이 있다.
Last updated