Good Code
The good version makes the SFC boundary visible: the component receives the exact display fields it needs and renders one card.
Lesson 01
Keep Vue single-file components focused on one UI responsibility with inputs visible at the component boundary.
<script setup lang="ts">
type ReviewCardProps = {
title: string;
reviewerName: string;
status: "approved" | "changes-requested";
};
// Props keep display data at the component boundary.
defineProps<ReviewCardProps>();
</script>
<template>
<article class="review-card">
<h2>{{ title }}</h2>
<p>{{ reviewerName }} marked this review as {{ status }}.</p>
</article>
</template><script setup>
import { useRoute } from "vue-router";
import { useSession } from "@/stores/session";
// This SFC owns routing, session state, fetching, and display at once.
const route = useRoute();
const session = useSession();
const response = await fetch("/api/reviews/" + route.params.id);
const review = await response.json();
</script>
<template>
<section>
<h2>{{ session.project.name }}: {{ review.title }}</h2>
<p>{{ review.reviewer.name }} marked this review as {{ review.status }}.</p>
</section>
</template>The good version makes the SFC boundary visible: the component receives the exact display fields it needs and renders one card.
The bad version mixes routing, session state, fetching, and display. A reviewer has to understand several app concerns before knowing what the component is responsible for.