3. 카테고리 목록

카테고리는 헤더에 표시한다.

ProductList 페이지처럼 훅을 이용해 카테고리를 가져올테다.

Store

ProductStore이다.

@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;
  }
}

CategoriesStore 이다.

@singleton()
@Store()
export default class CategoriesStore {
  categories: Category[] = [];

  async fetchCategories() {
    this.setCategories([]);

    const categories = await apiService.fetchCategories();

    this.setCategories(categories);
  }

  @Action()
  setCategories(categories: Category[]) {
    this.categories = categories;
  }
}

처음 ProductsStore를 만들었을땐 apiBaseUrl로 바로 axios 요청을 보낸다.

store가 늘어나며 이 부분의 중복이 반복되기 때문에

CategoriesStore 에서는 apiService를 이용한다.

ApiService

const API_BASE_URL = process.env.API_BASE_URL
                     || 'https://shop-demo-apisample';

export default class ApiService {
  private instance = axios.create({
    baseURL: API_BASE_URL,
  });

  async fetchCategories(): Promise<Category[]> {
    const { data } = await this.instance.get('/categories');
    const { categories } = data;
    return categories;
  }

  async fetchProducts(): Promise<ProductSummary[]> {
    const { data } = await this.instance.get('/products');
    const { products } = data;
    return products;
  }
}

export const apiService = new ApiService();

저수준에 가까운 fetch 코드를 apiService로 관심사를 분리해준 것.

카테고리별 상품 목록

useFetchProducts로 id를 받아 해당하는 상품들을 보여준다.

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>
  );
}

view - hook - store - apiService

Last updated