ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,40 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class LottoRankResult {
+    private List<Rank> ranks;
+
+    public LottoRankResult(WinningLotto winningLotto, LottoTicket lottoTicket) {
+        this.ranks = new ArrayList<>();
+
+        for (Lotto lotto : lottoTicket.getAllLottoGames()) {
+            ranks.add(
+                    Rank.valueOf(
+                            winningLotto.getCountOfSameNumber(lotto),
+                            winningLotto.isWinningBonus(lotto)
+                    )
+            );
+        }
+    }
+
+    public int getCount(Rank rank) {
+        return (int) ranks.stream().filter(t -> t.equals(rank)).count();
+    }
+
+    public Money getTotalWinningMoney() {
+        Money earnings = Money.ZERO;
+
+        for (Rank rank : ranks) {
+            earnings = earnings.add(rank.getWinningMoney());
+        }
+
+        return earnings;
+    }
+
+    public double getEarningsRate(Money invest) {
+        Money earnings = getTotalWinningMoney();
+
+        return (double)(earnings.intValue()) / invest.intValue() * 100.0;
+    }
+
+}
\ No newline at end of file

리뷰: 뭔가 이름이 결과를 담는 데이터 그릇 같은 느낌이라
LottoCalculator
LottoResultCalculator
LottoRankCalculator
같은 네이밍으로 변경해보면 어떨까요?

그에 맞춰서 메서드 네이밍도 변경하면 단순히 set 된 데이터를 get 하는 것보다 
상태와 행위를 갖는 객체지향적인 네이밍이 될 것 같다는 생각이 듭니다
@@ -0,0 +1,22 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class Lottos {
+    private List<Lotto> lottos;
+
+    public Lottos() {
+        this.lottos = new ArrayList<>();
+    }
+
+    public List<Lotto> getLottos() {
+        return lottos;
+    }
+
+    public void addLotto(Lotto lotto) {
+        lottos.add(lotto);
+    }
+
+    public int getSize() {
+        return lottos.size();
+    }
+}

리뷰: Lottos 가 가지는 행위가 하나도 없는데요, 
다른 객체에서 위임할만한게 없을까요?
get이 사용되고 있다는 것은 Lottos 의 tell dont ask 원칙이 안지켜지고 있다는 뜻이고,
여기로 위임할만한 책임이 산재해 있다는 뜻이기도 합니다.
@@ -0,0 +1,29 @@
+import java.util.List;
+
+public class WinningLotto {
+    private Lotto winningLotto;
+    private LottoNo bonusNo;
+
+    public WinningLotto(List<LottoNo> winningLottoNumbers, LottoNo lottoNo) {
+        if (winningLottoNumbers == null) {
+            throw new IllegalArgumentException("'lotto' must not be null");
+        }
+        if (lottoNo == null) {
+            throw new IllegalArgumentException("'lottoNo' must not be null");
+        }
+
+        this.winningLotto = new Lotto(winningLottoNumbers);
+        this.bonusNo = lottoNo;
+    }
+
+    public int getCountOfSameNumber(Lotto purchasedLotto) {
+        return (int) winningLotto.getLottoNums()
+                .stream()
+                .filter(purchasedLotto.getLottoNums()::contains)
+                .count();
+    }
+
+    public boolean isWinningBonus(Lotto purchasedLotto) {
+        return purchasedLotto.getLottoNums().contains(bonusNo);
+    }
+}

리뷰: Lotto를 상속 받을 수도 있었는데 이렇게 합성을 사용하셨네요. 👍 
혹시라도 우연히 이렇게 구현하신거라면, 
상속과 합성을 구글링 해보시면 관련 자료를 찾으실 수 있을겁니다 ~
@@ -0,0 +1,43 @@
+import java.util.Scanner;
+
+public class LottoApplication {
+    private static boolean APP_SUCCESS = false;
+
+    public static void main(String[] args) {
+        runUntilAppSuccess();
+    }
+
+    public static void runUntilAppSuccess() {
+        while (!APP_SUCCESS) {
+            run();
+        }
+    }
+
+    public static void run() {
+        final Scanner scanner = new Scanner(System.in);
+        int countOfManualLotto;
+
+        try {
+            LottoService lottoService = new LottoService(
+                    InputView.scanMoney(scanner),
+                    countOfManualLotto = InputView.scanCountOfManualLotto(scanner),
+                    InputView.scanNumbersOfManualLotto(scanner, countOfManualLotto),
+                    new LottoSeller()
+            );
+
+            lottoService.purchaseLottoTicket();
+            lottoService.printPurchaseResult();
+
+            lottoService.setWinningLotto(
+                    InputView.scanWinningLotto(scanner),
+                    InputView.scanBonusNo(scanner)
+            );
+
+            lottoService.printWinningResult();
+
+            APP_SUCCESS = true;
+        } catch (OutOfConditionException | IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+    }
+}

리뷰: LottoGame 이라는 네이밍은 어떨까요
@@ -0,0 +1,43 @@
+import java.util.Scanner;
+
+public class LottoApplication {
+    private static boolean APP_SUCCESS = false;
+
+    public static void main(String[] args) {
+        runUntilAppSuccess();
+    }
+
+    public static void runUntilAppSuccess() {
+        while (!APP_SUCCESS) {
+            run();
+        }
+    }
+
+    public static void run() {
+        final Scanner scanner = new Scanner(System.in);
+        int countOfManualLotto;
+
+        try {
+            LottoService lottoService = new LottoService(
+                    InputView.scanMoney(scanner),
+                    countOfManualLotto = InputView.scanCountOfManualLotto(scanner),
+                    InputView.scanNumbersOfManualLotto(scanner, countOfManualLotto),
+                    new LottoSeller()
+            );
+
+            lottoService.purchaseLottoTicket();
+            lottoService.printPurchaseResult();
+
+            lottoService.setWinningLotto(
+                    InputView.scanWinningLotto(scanner),
+                    InputView.scanBonusNo(scanner)
+            );
+
+            lottoService.printWinningResult();
+
+            APP_SUCCESS = true;
+        } catch (OutOfConditionException | IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+    }
+}

리뷰: lottoService 에 set 하고 get 하고 절차지향적인 방식으로 코드가 짜여져 있습니다.
모든 로직이 lottoService 를 통하면서 결국 이 클래스는 점점 비대해질텐데요
좋은 개선 방법이 없을까요~?
@@ -0,0 +1,48 @@
+import java.util.Arrays;
+
+public enum Rank {
+    FIRST(6, 2000000000),
+    SECOND(5, 30000000),
+    THIRD(5, 1500000),
+    FOURTH(4, 50000),
+    FIFTH(3, 5000),
+    MISS(0, 0);
+
+    private int countOfMatch;
+    private Money winningMoney;
+
+    Rank(int countOfMatch, int winningMoney) {
+        this.countOfMatch = countOfMatch;
+        this.winningMoney = Money.valueOf(winningMoney);
+    }
+
+    public static Rank valueOf(int countOfGame, boolean matchBonus) {
+        if (countOfGame == SECOND.getCountOfMatch()) {
+            return getSecondOrThird(matchBonus);
+        }
+
+        return Arrays.stream(values())
+                .filter(r -> countOfGame == r.countOfMatch)
+                .findFirst()
+                .orElse(MISS);
+    }
+
+    public static Rank[] valuesNotMiss() {
+        return new Rank[]{FIRST, SECOND, THIRD, FOURTH, FIFTH};
+    }
+
+    private static Rank getSecondOrThird(boolean matchBonus) {
+        if (matchBonus)
+            return SECOND;
+        return THIRD;
+    }
+
+    public int getCountOfMatch() {
+        return countOfMatch;
+    }
+
+    public Money getWinningMoney() {
+        return winningMoney;
+    }
+
+}

리뷰: 중괄호가 빠졌습니다
@@ -0,0 +1,21 @@
+public class RankResult {
+    private Rank rank;
+    private int countOfRank;
+
+    RankResult(Rank rank) {
+        this.rank = rank;
+        this.countOfRank = 0;
+    }
+
+    public Rank getRank() {
+        return rank;
+    }
+
+    public int getCountOfRank() {
+        return countOfRank;
+    }
+
+    public void countUp(int count) {
+        countOfRank += count;
+    }
+}

리뷰: 데이터들을 클래스로 묶는 것이 객체지향은 아닙니다~
RankResult 도 결국 데이터와 get 만 가지고 있고,
유의미한 행위가 없습니다 ㅠㅠ 
불필요한 객체가 아닌지, 유의미한 행위를 가진 객체로 만들려면 어떤 행위를 부여해야하는지
고민해보시면 좋을 것 같아요~
@@ -0,0 +1,50 @@
+import java.util.List;
+
+public class LottoSeller {
+    private LottoPurchaseService lottoPurchaseService;
+    private Money change;
+
+    public LottoSeller() {
+        change = Money.ZERO;
+        lottoPurchaseService = new LottoPurchaseService();
+    }
+
+    public LottoTicket sellTicketTo(LottoUser lottoUser) throws OutOfConditionException {
+        Money investMoney = LottoPurchaseService
+                .validatePurchase(
+                        lottoUser.getInvestMoney(),
+                        lottoUser.getCountOfManualLotto()
+                );
+
+        this.change = LottoPurchaseService
+                .calculateChange(investMoney);
+
+        return lottoPurchaseService
+                .createLottoTicket(
+                        investMoney,
+                        getCountOfAutoGame(investMoney, lottoUser.getCountOfManualLotto()),
+                        changeToLottos(lottoUser.getNumbersOfManualLottos())
+                );
+    }
+
+    public int getCountOfAutoGame(Money investMoney, int countOfManualLotto) {
+        return investMoney.divideBy(LottoPurchaseService.LOTTO_PRICE).intValue()
+                - countOfManualLotto;
+    }
+
+    private Lottos changeToLottos(List<List<LottoNo>> numbers0fManualLottos) {
+        Lottos manualLottos = new Lottos();
+
+        for (List<LottoNo> lottoNums : numbers0fManualLottos) {
+            manualLottos.addLotto(
+                    lottoPurchaseService.createManualLotto(lottoNums)
+            );
+        }
+
+        return manualLottos;
+    }
+
+    public Money getChange() {
+        return change;
+    }
+}

리뷰: Service 라는 네이밍을 쓰시는걸로 봐서
웹 쪽 자료를 보신 것 같은데,
controller, service, repository 
이런 layered architecture 는 지금 저희가 하고 있는 객체지향과 거리가 좀 있습니다 ~

service 라는 네이밍을 사용하기보다는 좀 더 구체적이고 누구나 글 읽듯이 볼 수 있는 네이밍을 하시면
해당 객체에 부여하는 책임과 행위들도 달라지게 됩니다 ~
네이밍은 단순히 시각적인 효과 그 이상의 가치를 가지고 있습니다
@@ -0,0 +1,50 @@
+import java.util.List;
+
+public class LottoSeller {
+    private LottoPurchaseService lottoPurchaseService;
+    private Money change;
+
+    public LottoSeller() {
+        change = Money.ZERO;
+        lottoPurchaseService = new LottoPurchaseService();
+    }
+
+    public LottoTicket sellTicketTo(LottoUser lottoUser) throws OutOfConditionException {
+        Money investMoney = LottoPurchaseService
+                .validatePurchase(
+                        lottoUser.getInvestMoney(),
+                        lottoUser.getCountOfManualLotto()
+                );
+
+        this.change = LottoPurchaseService
+                .calculateChange(investMoney);
+
+        return lottoPurchaseService
+                .createLottoTicket(
+                        investMoney,
+                        getCountOfAutoGame(investMoney, lottoUser.getCountOfManualLotto()),
+                        changeToLottos(lottoUser.getNumbersOfManualLottos())
+                );
+    }
+
+    public int getCountOfAutoGame(Money investMoney, int countOfManualLotto) {
+        return investMoney.divideBy(LottoPurchaseService.LOTTO_PRICE).intValue()
+                - countOfManualLotto;
+    }
+
+    private Lottos changeToLottos(List<List<LottoNo>> numbers0fManualLottos) {
+        Lottos manualLottos = new Lottos();
+
+        for (List<LottoNo> lottoNums : numbers0fManualLottos) {
+            manualLottos.addLotto(
+                    lottoPurchaseService.createManualLotto(lottoNums)
+            );
+        }
+
+        return manualLottos;
+    }
+
+    public Money getChange() {
+        return change;
+    }
+}

리뷰: 점 하나 찍을 때는 줄바꿈을 안하시는게 일반적입니다.
메소드 파라미터도 3개 이상부터 엔터를 치시는게 어떨까요?
@@ -0,0 +1,42 @@
+import java.util.List;
+
+public class LottoService {
+    LottoUser lottoUser;
+    LottoSeller lottoSeller;
+    LottoTicket purchasedLottoTicket = null;
+    WinningLotto winningLotto = null;
+    PurchaseResultView purchaseResultView = null;
+    WinningResultView winningResultView = null;
+
+    public LottoService(Money investMoney, int countOfManualLotto, List<List<LottoNo>> numbersOfManualLotto,
+                        LottoSeller lottoSeller) {
+        this.lottoUser = new LottoUser(investMoney, countOfManualLotto, numbersOfManualLotto);
+        this.lottoSeller = lottoSeller;
+    }
+    
+    public LottoTicket purchaseLottoTicket() throws OutOfConditionException {
+        purchasedLottoTicket = lottoSeller.sellTicketTo(lottoUser);
+        lottoUser.setLottoTicket(purchasedLottoTicket);
+        
+        return purchasedLottoTicket;
+    }
+
+    public void printPurchaseResult() {
+        purchaseResultView = new PurchaseResultView();
+
+        purchaseResultView.notifyIfChangeLeft(lottoSeller);
+        purchaseResultView.printPurchasedTicket(lottoUser);
+    }
+
+    public void setWinningLotto(List<LottoNo> winningLottoNumbers, LottoNo bonusNo) {
+        winningLotto =  new WinningLotto(winningLottoNumbers, bonusNo);
+    }
+
+    public void printWinningResult() {
+        winningResultView = new WinningResultView();
+
+        winningResultView.printWinningResult(winningLotto, purchasedLottoTicket);
+        winningResultView.printEarningsRate(winningLotto, purchasedLottoTicket);
+    }
+
+}

리뷰: set을 사용하지 않는다는 객체지향 생활체조 규칙을 적용해보시면
코드의 설계가 달라질 것 같습니다
@@ -0,0 +1,43 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class LottoTicket {
+    private Money ticketPrice;
+    private Lottos autoLottos;
+    private Lottos manualLottos;
+
+    public LottoTicket(Money ticketPrice, Lottos autoLottos, Lottos manualLottos) {
+        this.ticketPrice = ticketPrice;
+        this.autoLottos = autoLottos;
+        this.manualLottos = manualLottos;
+    }
+
+    public List<Lotto> getAllLottoGames() {
+        List<Lotto> lottos = new ArrayList<>();
+
+        lottos.addAll(getManualLottos());
+        lottos.addAll(getAutoLottos());
+
+        return lottos;
+    }
+
+    public List<Lotto> getAutoLottos() {
+        return autoLottos.getLottos();
+    }
+
+    public List<Lotto> getManualLottos() {
+        return manualLottos.getLottos();
+    }
+
+    public int getCountOfAutoLotto() {
+        return autoLottos.getSize();
+    }
+
+    public int getCountOfManualLotto() {
+        return manualLottos.getSize();
+    }
+
+    public Money getTicketPrice() {
+        return ticketPrice;
+    }
+}

리뷰: 여기도 행위가 없고 데이터 + getter 뿐이네요.
그런데 이렇게 클래스를 나눠보려고 최대한 시도하신 점 👍
@@ -0,0 +1,35 @@
+import java.util.List;
+
+public class LottoUser {
+    private Money investMoney;
+    private int countOfManualLotto;
+    private List<List<LottoNo>> numbersOfManualLottos;
+
+    private LottoTicket lottoTicket;
+
+    public LottoUser(Money investMoney, int countOfManualLotto, List<List<LottoNo>> numbersOfManualLottos) {
+        this.investMoney = investMoney;
+        this.countOfManualLotto = countOfManualLotto;
+        this.numbersOfManualLottos = numbersOfManualLottos;
+    }
+
+    public void setLottoTicket(LottoTicket lottoTicket) {
+        this.lottoTicket = lottoTicket;
+    }
+
+    public LottoTicket getLottoTicket() {
+        return lottoTicket;
+    }
+
+    public int getCountOfManualLotto() {
+        return countOfManualLotto;
+    }
+
+    public List<List<LottoNo>> getNumbersOfManualLottos() {
+        return numbersOfManualLottos;
+    }
+
+    public Money getInvestMoney() {
+        return investMoney;
+    }
+}

리뷰: 여기도 setter getter 뿐 이네요 ㅠ
@@ -0,0 +1,65 @@
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class LottoPurchaseService {
+    public final static Money LOTTO_PRICE = Money.valueOf(1000);
+
+    public static Money validatePurchase(Money inputMoney, int countOfManualLotto) throws OutOfConditionException {
+        if (inputMoney.intValue() < LOTTO_PRICE.intValue()) {
+            throw new OutOfConditionException(LOTTO_PRICE + "원 이상이 필요합니다.");
+        }
+
+        if (countOfManualLotto * LOTTO_PRICE.intValue() > inputMoney.intValue()) {
+            throw new IllegalArgumentException("금액이 작아 원하는 만큼 수동 로또를 살 수 없습니다.");
+        }
+
+        return inputMoney;
+    }
+
+    public static Money calculateChange(Money inputMoney) {
+        return Money.valueOf(inputMoney.intValue() % LOTTO_PRICE.intValue());
+    }
+
+    public Lotto createManualLotto(List<LottoNo> lottoNums) {
+        Collections.sort(lottoNums);
+        return new Lotto(lottoNums);
+    }
+
+    public Lotto createAutoLotto() {
+        List<LottoNo> auto = new ArrayList<>(shuffleAllLottoNo().subList(0, 6));
+        Collections.sort(auto);
+
+        return new Lotto(auto);
+    }
+
+    public Lottos createAutoLottos(int countOfAutoLotto) {
+        Lottos autoLottos = new Lottos();
+
+        for (int i = 0; i < countOfAutoLotto; i++) {
+            autoLottos.addLotto(
+                    createAutoLotto()
+            );
+        }
+
+        return autoLottos;
+    }
+
+    public LottoTicket createLottoTicket(Money ticketPrice, int countOfAutoLotto, Lottos manualLottos) {
+        return new LottoTicket(
+                ticketPrice,
+                createAutoLottos(countOfAutoLotto),
+                manualLottos);
+    }
+
+    private List<LottoNo> shuffleAllLottoNo() {
+        List<LottoNo> lottoNums = new ArrayList<>();
+
+        for (int i = 1; i <= 45; i++) {
+            lottoNums.add(new LottoNo(i));
+        }
+        Collections.shuffle(lottoNums);
+
+        return lottoNums;
+    }
+}

리뷰: 데이터와 프로세스가 따로 있는 것 == 절차지향 프로그래밍

현 상황 : 
데이터 = LottoSeller, Ticket, User 등 (데이터 + getter)
프로세스 = Service (데이터 get 해서 로직 처리)

답 : MVC와 layered architecture를 잊고 view 와 비즈니스 로직을 분리하는 것만 기억하고 짜보기
@@ -0,0 +1,65 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+public final class InputView {
+
+    public static Money scanMoney(Scanner scanner) {
+        System.out.println("\n구입금액을 입력해 주세요.");
+
+        return Money.valueOf(Integer.parseInt(scanner.nextLine()));
+    }
+
+    public static int scanCountOfManualLotto(Scanner scanner) {
+        System.out.println("\n수동으로 구매할 로또 수를 입력해 주세요.");
+
+        return Integer.parseInt(scanner.nextLine());
+    }
+
+    public static List<List<LottoNo>> scanNumbersOfManualLotto(Scanner scanner, int countOfManualGame) {
+        System.out.println("\n수동으로 구매할 번호를 입력해 주세요.");
+
+        List<List<LottoNo>> manualLotto = new ArrayList<>();
+        String input = scanner.nextLine();
+        int count = countOfManualGame;
+
+        while (!input.isEmpty() && count != 0) {
+            count--;
+            addScannedNumbers(manualLotto, input);
+            input = scanner.nextLine();
+        }
+
+        return manualLotto;
+    }
+
+    private static void addScannedNumbers(List<List<LottoNo>> manualLotto, String input) {
+        manualLotto.add(
+                Arrays.asList(input.replaceAll(" ", "").split(","))
+                        .stream()
+                        .map(Integer::parseInt)
+                        .map(LottoNo::new)
+                        .collect(Collectors.toList())
+        );
+    }
+
+    public static List<LottoNo> scanWinningLotto(Scanner scanner) {
+        System.out.println("\n지난 주 당첨 번호를 입력해 주세요.");
+
+        return Arrays.asList(scanner.nextLine()
+                .replaceAll(" ", "")
+                .split(","))
+                .stream()
+                .map(Integer::parseInt)
+                .map(LottoNo::new)
+                .collect(Collectors.toList());
+    }
+
+    public static LottoNo scanBonusNo(Scanner scanner) {
+        System.out.println("보너스 볼을 입력해 주세요.");
+
+        return new LottoNo(Integer.parseInt(scanner.nextLine()));
+    }
+
+}

리뷰: view 에서는 데이터를 scan 해오는 책임만 있습니다.
지금은 변환 로직까지 여기서 처리하고 있네요~!
@@ -0,0 +1,29 @@
+public final class PurchaseResultView {
+    public void notifyIfChangeLeft(LottoSeller seller) {
+        if (!seller.getChange().equals(Money.ZERO)) {
+            System.out.println("잔돈 " + seller.getChange() + "원이 남았습니다.");
+            System.out.println();
+        }
+    }
+
+    public void printPurchasedTicket(LottoUser lottoUser) {
+        LottoTicket lottoTicket = lottoUser.getLottoTicket();
+
+        System.out.println(
+                "수동으로 " + lottoTicket.getCountOfManualLotto() +
+                "장, 자동으로 " + lottoTicket.getCountOfAutoLotto() +
+                "개를 구매했습니다."
+        );
+
+        for (Lotto manualGame : lottoTicket.getManualLottos()) {
+            System.out.println(manualGame.getNums());
+        }
+
+        for (Lotto autoGame : lottoTicket.getAutoLottos()) {
+            System.out.println(autoGame.getNums());
+        }
+
+        System.out.println();
+    }
+
+}

리뷰: finall class 로 하신 이유가 궁금합니다~
@@ -1,23 +1,20 @@
 <template>
-  <button
-    @click="
-      () => {
-        if (!props.disabled) props.onClick();
-      }
-    "
-    :class="getNextButtonStyle()"
-  >
-    <slot></slot>
+  <button @click="handleNextButtonClick" :class="getNextButtonStyle()">
+    <slot />
   </button>
 </template>
 
 <script setup lang="ts">
 const props = defineProps<{
-  isPrimary?: boolean;
+  isPrimary?: boolean | undefined;
   onClick: () => void;
-  disabled?: boolean;
+  disabled?: boolean | undefined;
 }>();
 
+const handleNextButtonClick = () => {
+  if (!props.disabled) props.onClick();
+};
+
 const getNextButtonStyle = () => ({
   'h-fit w-[340px] rounded-2xl border-0 p-6 text-large font-bold mb-6': true,
   'bg-primary-light dark:bg-primary-dark': props.isPrimary,

리뷰: 단순 궁금증으로 질문드립니다.
undefined를 타입으로 지정하신 이유가 있을까요?

NextButton.vue의 부모 컴포넌트에서 isPrimary 값을 부여하지 않을 때가 있어 undefined를 포함한 것으로 보이는데,
이 경우는 ? 만으로도 충분히 표현이 된 것 같습니다.
특히 boolean이기때문에 undefined일 때 falsy하게 인식이 될 것 같은데
추가하신 이유가 궁금합니다~
@@ -3,8 +3,8 @@
     <p class="text-medium font-semi_bold">{{ title }}</p>
     <div class="flex gap-x-3">
       <button
-        v-for="size in sizes"
-        :key="size.id"
+        v-for="(size, index) in sizes"
+        :key="getButtonKey(size, index)"
         class="flex flex-col items-center justify-between gap-y-[10px]"
         @click="handleSizeClick(size)"
       >
@@ -23,9 +23,10 @@
 </template>
 
 <script setup lang="ts">
-import { Size } from '@interface/goods';
+import { Size } from '@interface/sizes';
 import { useUserSelectStore } from '@store/storeUserSelect';
 import { PLACE_HOLD_IMAGE_URL } from '@constants';
+import { storeToRefs } from 'pinia';
 
 defineProps<{
   title: string;
@@ -38,11 +39,12 @@ const getImageWidth = (size: Size) => {
   return 74;
 };
 
-const { userSelect, setUserSelectSizeId, setUserSelectSizeValue } =
-  useUserSelectStore();
+const store = useUserSelectStore();
+const { userSelect } = storeToRefs(store);
+const { setUserSelectSizeId, setUserSelectSizeValue } = store;
 
 const handleSizeClick = (size: Size) => {
-  if (userSelect.sizeId === size.id) {
+  if (userSelect.value.sizeId === size.id) {
     setUserSelectSizeId(0);
     setUserSelectSizeValue(0);
     return;
@@ -51,11 +53,13 @@ const handleSizeClick = (size: Size) => {
   setUserSelectSizeValue(size.value);
 };
 
+const getButtonKey = (size: Size, index: number) => `size-${size.id}-${index}`;
+
 const getUserSelectStyle = (size: Size) => ({
   'flex h-[74px] w-[74px] items-center justify-center rounded-2xl border-[3px] bg-gray_01-light dark:bg-gray_01-dark':
     true,
-  'border-secondary-light': userSelect.sizeId === size.id,
+  'border-secondary-light': userSelect.value.sizeId === size.id,
   'border-gray_01-light dark:border-gray_01-dark':
-    userSelect.sizeId !== size.id,
+    userSelect.value.sizeId !== size.id,
 });
 </script>

리뷰: storeToRefs 를 사용해서 반응성을 살리셨네요 👍