내부 컴포넌트에서 합산된 결과를 부모 컴포넌트에 올릴 수 있을까요?

장바구니 기능을 개발하고 있는데, 딜레마에 빠졌습니다.
장바구니 (flatlist) 별로 존재하는 물품 (map) 항목에서, 장바구니별로 각 물품의 금액 합계를 내려고 합니다.

먼저 flatlist에 들어간 renderItem은 다음과 같습니다.

<CartItem
  cartItem={cartItem}
  product={item.product}
  errorMsg={errorMsg}
  onChange={(current, currentItem) =>
    updateItem(cartId, currentItem, cartItem, current, token)
  }
  cartStatus={status}
  cartRemove={() => remove(cartId, token)}
  cartItemRemove={(currentItem) =>
    removeItem(cartId, currentItem, cartItem, token)
  }
/>

다음은 CartItem 컴포넌트 안에서 뿌리는 데이터는 다음과 같습니다.

{cartItem.map((item) => {
  const findMatch = product.find((info) => info._id === item._id);
  if (!findMatch) return null;

  const matchItem = ensure<CartProductType>(findMatch);
  const option = ensure<ProductOptions>(
    matchItem.option.find((info) => info.title === item.option),
  );

  const totalPrice = item.amount > 1 ? option.price * item.amount : option.price;
  const totalWeight = item.amount > 1 ? matchItem.weight * item.amount : matchItem.weight;
  const leftStock = option.stock - option.order;
  const available = matchItem.useYN;
  const stockAvailable = option.stock === -1 ? true : leftStock > 0;
  const maxStock = calculateMaxStock(option.stock, matchItem.limitAmount, leftStock);

  if (stockAvailable) {
    result.price += option.price * item.amount;
    result.count += item.amount;
    result.weight += matchItem.weight * item.amount;
  }

  return (
    <ProductSelect
      key={matchItem._id + option.title}
      title={matchItem.title}
      detail={`${totalPrice}원 · ${totalWeight}g`}       
      imageUrl={`${STORAGE_SERVER_URL}/${matchItem.cover[0]}`}
      available={available}
      stockAvailable={stockAvailable}
      status={cartStatus}
      error={errorMsg}
      option={option.title}
      onRemovePress={() => removeButtonPress(item)}>
      {!available ? (
        productUnavailable
      ) : !stockAvailable ? (
        productOutofStock
      ) : (
        <Spinner
          disabled={cartStatus !== 0}
          current={item.amount}
          min={1}
          max={maxStock}
          onChange={(current) => onItemChange(current, item)}
        />
      )}
    </ProductSelect>
  );
})}

map으로 구현하는 부분이 너무 길어서 따로 컴포넌트를 만들어서 분리시켰는데,

 if (stockAvailable) {
    result.price += option.price * item.amount;
    result.count += item.amount;
    result.weight += matchItem.weight * item.amount;
  }

부분에서 result가 부모 컴포넌트로 올라가야 나머지 뷰에 해당 값을 뿌릴 수 있습니다.
그럼 이 부분을 수정하기 위해서

  1. result 계산식을 위로 올리고 밑에서는 그냥 렌더링만 하도록 한다 → map() 함수가 두 번 호출되기 때문에 결과적으로는 성능적 손해를 봄 (장바구니가 항목별로 1, 2개가 아니라 30, 40개는 기본이고 100개도 찍는 경우도 있습니다!)
  2. 다시 원래대로 돌린다 → 코드가 너무 길어서 가독성이 처참해지고 side-effect 처리가 제대로 안 됨

이라는 딜레마를 겪고 있습니다. useContext를 사용할까 생각도 해봤는데, 단일 항목이라면 모를까 flatlist renderItem 함수 안에 context를 넣어서 항목별로 provider를 넣어줬을때 이게 작동이 가능한지에 대해 근본적인 의문도 듭니다.

renderItem(() => {
const Result = createContext(result);

return (
<Result.Provider value={result}>
    <CartItem
      cartItem={cartItem}
      product={item.product}
      errorMsg={errorMsg}
      onChange={(current, currentItem) =>
        updateItem(cartId, currentItem, cartItem, current, token)
      }
      cartStatus={status}
      cartRemove={() => remove(cartId, token)}
      cartItemRemove={(currentItem) =>
        removeItem(cartId, currentItem, cartItem, token)
      }
    />
  </Result.Provider>
)});

이런 식으로 구현이 될텐데, 이게 가능한 건가요?
여러모로 머리가 아픈 상황입니다…

Page 단에서 렌더링에 관련된 state를 자식으로 내려주는 1번에 찬성합니다. Provider 사용하시면 Consumer 리렌더링이 많이 걸릴 것 같습니다. 여쭤보고 싶은건 map() 이 어떤 부분에서 두번 호출될까요?
별개로 성능을 고려하신다면, 매핑해주는 컴포넌트들에 속한(renderItems와 비슷한) arrow function을 부모 컴포넌트에서 함수로 할당해주시는게 좋을 것 같아요!

컴포넌트를 분리하고 result를 계산한다고 하면,
합계 계산할때 cartItem을 사용하기 때문에 계산할때 map 한번, 렌더링할 때 map 한번 돕니다.

말씀하신 로직이 불가피하게 2번 사용된다고 해도, Provider는 기피하시는게 좋을 것 같습니다. 구독하는 value의 참조값이 변해도 리렌더링이 걸리기도하고, 뭔가 보편적인 코드 패턴에서 벗어나는 구조가 된다면 관리하기도 까다로워질 것 같아서요! 정말 컴포넌트 트리 depth가 깊고, global한 상태가 필요하다면, Provider대신 Recoil을 도입해보시는걸 추천드립니다!