> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 카트 라인에 메타필드 데이터 표시하기

> registerCartEnricher를 사용해 Shopify Storefront API의 메타필드를 모든 카트 라인에 가져와 렌더링하는 Cart SDK 사용 사례예요.

카트는 Shopify의 Ajax API가 알려주는 것만 알아요: 제목, 가격, 수량, 속성. 메타필드는 알지 못해요. **cart enricher**는 Storefront API에서 추가 상품 또는 옵션 필드를 가져와 일치하는 모든 라인에 첨부하므로, 배송 예상일, "별도 배송" 경고, 성분 목록 등 상품에 저장한 무엇이든 표시할 수 있어요.

일반적인 용도: 상품별 배송 기간, 알레르기 유발 성분 또는 성분 배지, 커스텀 "재고 부족" 플래그, 로열티 포인트 배수, 구독자 전용 가격.

<div id="register-the-enricher">
  ## enricher 등록하기
</div>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'delivery',
  onType: 'Product',
  fragment: `
    deliveryWindow: metafield(namespace: "custom", key: "delivery_window") { value }
    shipsSeparately: metafield(namespace: "custom", key: "ships_separately") { value }
  `,
});
```

세 가지 필드:

| 필드         | 설명                                                                        |
| ---------- | ------------------------------------------------------------------------- |
| `id`       | 결과의 네임스페이스이며, `line.metadata[id]`에 담겨요. 고유해야 하고, 같은 `id`로 두 번째 등록하면 무시돼요. |
| `onType`   | `'Product'` 또는 `'ProductVariant'`. 조인 키이기도 하므로 상품 ID 대 옵션 ID를 결정해요.       |
| `fragment` | Storefront 쿼리에 삽입되는 GraphQL 필드 선택(바깥 중괄호 없이). 중괄호는 균형을 이뤄야 해요.            |

카트가 로드되거나 변경될 때마다 Aftersell은 카트의 모든 상품 또는 옵션에 대해 fragment를 가져와요. 이 요청은 **논블로킹**이에요: 카트는 즉시 렌더링되고 데이터가 도착하면 `cart_updated`를 다시 발생시켜요. 느리거나 실패하는 fragment가 카트를 지연시키거나 망가뜨리는 일은 절대 없어요.

<div id="read-the-data">
  ## 데이터 읽기
</div>

enrichment는 비동기이므로 첫 번째 요청이 resolve될 때까지 `line.metadata.delivery`는 `undefined`예요. 항상 읽기를 가드하세요.

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    const deliveryWindow = line.metadata.delivery?.deliveryWindow?.value;
    if (!deliveryWindow) return; // not fetched yet

    console.log(line.title, 'arrives in', deliveryWindow);
  });
});
```

<div id="render-it-in-the-cart">
  ## 카트에서 렌더링하기
</div>

enrichment는 데이터를 라인에 올려놓고, React 모드의 [커스텀 코드 블록](/ko/aftersell/cart/custom-code-blocks)이 그려요. 블록을 **Cart items 하위 블록**으로 추가하면 라인마다 한 번씩 렌더링되고 해당 라인을 `props.line`으로 받아요:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  const data = props.line?.metadata?.delivery;
  const window_ = data?.deliveryWindow?.value;

  if (!window_) return null;

  return (
    <div className="cart-external-custom-code_html" style={{ fontSize: '12px', opacity: 0.7 }}>
      Arrives in {window_}
    </div>
  );
}
```

<Warning>
  enrichment로 얻은 값은 Storefront API에서 **있는 그대로, 정제되지 않은 채** 돌아와요. 위와 같이 텍스트로 렌더링하고, 절대 `dangerouslySetInnerHTML`이나 원시 HTML 작성으로 렌더링하지 마세요.
</Warning>

<div id="variant-level-data">
  ## 옵션 수준 데이터
</div>

메타필드가 상품이 아닌 옵션(variant)에 있을 때는 `onType: 'ProductVariant'`로 설정하세요:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'pricing',
  onType: 'ProductVariant',
  fragment: `
    anchorPrice: metafield(namespace: "custom", key: "anchor_price") { value }
    subscriberPrice: metafield(namespace: "custom", key: "subscriber_price") { value }
  `,
});
```

<div id="more-than-metafields">
  ## 메타필드 그 이상
</div>

fragment는 Storefront API 쿼리에 삽입되므로, 메타필드뿐 아니라 API가 `Product`나 `ProductVariant`에서 노출하는 모든 것이 작동해요:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerCartEnricher({
  id: 'productInfo',
  onType: 'Product',
  fragment: `
    tags
    vendor
    productType
    availableForSale
  `,
});
```

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
// Then: warn about anything from a drop-ship vendor.
window.aftersell.cart.events.on('cart_updated', (state) => {
  const hasDropship = state.items.some((line) => {
    const tags = line.metadata.productInfo?.tags;
    return tags?.includes('dropship');
  });
});
```

<div id="things-to-get-right">
  ## 제대로 처리해야 할 것들
</div>

* **모든 읽기를 가드하세요.** `metadata`의 기본값은 `{}`이고, 요청이 resolve될 때까지 여러분의 네임스페이스는 `undefined`예요. 카트는 항상 데이터 도착 전에 렌더링돼요.
* **각 `id`는 고유한 네임스페이스예요.** 다른 앱이 등록한 것을 포함해 여러 enricher가 충돌 없이 공존해요.
* **메타필드는 Storefront에서 보여야 해요.** Storefront API에 노출되지 않은 메타필드는 `null`을 반환해요. 아무것도 돌아오지 않으면 Shopify admin에서 정의를 확인하세요.
* **fragment는 작게 유지하세요.** 카트의 모든 상품에 대해, 카트가 변경될 때마다 실행돼요. 필요한 필드만 요청하고 전부 요청하지 마세요.
* **설정 시점에 등록하세요.** 훅이므로 Initialization 스크립트 맨 위에 두어야 해요.
* **중괄호는 균형을 이뤄야 해요.** fragment에 바깥 중괄호는 없어야 하지만, 중첩된 선택에는 각각 짝이 맞는 중괄호가 필요해요. 균형이 맞지 않는 fragment는 거부돼요.

<div id="where-to-go-next">
  ## 다음 단계
</div>

* **[`registerCartEnricher`](/ko/aftersell/cart/sdk-hooks#registercartenricher)**: 전체 훅 레퍼런스.
* **[커스텀 코드 블록](/ko/aftersell/cart/custom-code-blocks)**: 데이터 렌더링.
* **[Cart 객체](/ko/aftersell/cart/sdk-cart-object)**: 라인에서 `metadata`가 위치하는 곳.
