# Vue 3 Component Style Guide - Composition API

## Component Structure

Components should be structured in the following order:

1. `<template>`
2. `<script setup>`
3. `<style>`

## Order of Properties in `<script setup>`

1. **Type Imports** (if using TypeScript)

   ```ts
   import type { PropType } from "vue"
   import type { MyInterface } from "@/types"
   ```

2. **Component Imports**

   ```ts
   import { ref, computed, onMounted } from "vue"
   import BaseButton from "@/components/BaseButton.vue"
   ```

3. **Composable Imports**

   ```ts
   import { useRouter } from "vue-router"
   import { useStore } from "vuex"
   import { useMyComposable } from "@/composables/useMyComposable"
   ```

4. **Constants and Utilities**

   ```ts
   const ITEMS_PER_PAGE = 10
   const DEFAULT_THEME = "light"
   ```

5. **Component Options**

   ```ts
   // Props
   const props = defineProps<{
     title: string
     items?: string[]
     callback?: (id: number) => void
   }>()

   // Emits
   const emit = defineEmits<{
     "update:selected": [value: string]
     submit: [payload: { id: number; data: string }]
   }>()

   // Model
   const model = defineModel<string>({
     required: true,
     default: "",
   })

   // Expose (when needed)
   defineExpose({
     reset,
     validate,
   })
   ```

6. **Dependency Injection**

   ```ts
   // Provide
   provide("key", value)

   // Inject
   const injectedValue = inject("key")
   const injectedWithDefault = inject("key", defaultValue)
   ```

7. **Composable Usage**

   ```ts
   const router = useRouter()
   const store = useStore()
   const { data, loading } = useMyComposable()
   ```

8. **Local State**

   ```ts
   // Refs
   const count = ref(0)
   const name = ref("")

   // Reactive objects
   const form = reactive({
     username: "",
     password: "",
   })
   ```

9. **Computed Properties**

   ```ts
   const doubleCount = computed(() => count.value * 2)
   const isValid = computed(() => {
     return form.username && form.password.length >= 8
   })
   ```

10. **Methods**

    ```ts
    // Event handlers
    const handleClick = () => {
      count.value++
    }

    // Business logic
    const calculateTotal = () => {
      // calculation logic
    }

    // Async methods
    const fetchData = async () => {
      try {
        const response = await api.get("/data")
        // handle response
      } catch (error) {
        // handle error
      }
    }
    ```

11. **Watchers**

    ```ts
    // Simple watch
    watch(count, (newVal, oldVal) => {
      console.log(`Count changed from ${oldVal} to ${newVal}`)
    })

    // Watch with options
    watch(
      () => props.title,
      (newVal) => {
        // handle change
      },
      { immediate: true, deep: true },
    )

    // watchEffect
    watchEffect(() => {
      // reactive effect
    })
    ```

12. **Lifecycle Hooks**

    ```ts
    onBeforeMount(() => {
      // before mount logic
    })

    onMounted(() => {
      // mounted logic
    })

    onBeforeUnmount(() => {
      // cleanup logic
    })
    ```

## Complete Example

```vue
<template>
  <div class="users-list">
    <input v-model="searchQuery" placeholder="Search users..." />

    <div v-if="isLoading" class="loading">Loading...</div>

    <ul v-else>
      <li
        v-for="user in paginatedUsers"
        :key="user.id"
        @click="handleUserClick(user)"
      >
        {{ user.name }}
      </li>
    </ul>

    <BaseButton @click="currentPage++"> Next Page </BaseButton>
  </div>
</template>

<script setup lang="ts">
// Type imports
import type { PropType } from "vue"
import type { User } from "@/types"

// Component imports
import {
  ref,
  computed,
  watch,
  onMounted,
  provide,
  inject,
  defineModel,
} from "vue"
import BaseButton from "@/components/BaseButton.vue"

// Composable imports
import { useRouter } from "vue-router"
import { useUserStore } from "@/stores/user"

// Constants
const PAGINATION_LIMIT = 10
const THEME_KEY = "app-theme"

// Props
const props = defineProps<{
  users: User[]
  initialPage?: number
}>()

// Emits
const emit = defineEmits<{
  "update:page": [page: number]
  "user-selected": [user: User]
}>()

// Model
const searchQuery = defineModel<string>("search", {
  default: "",
})

// Provide/Inject
provide("theme", THEME_KEY)
const parentTheme = inject("parent-theme", "light")

// Composables
const router = useRouter()
const userStore = useUserStore()

// State
const currentPage = ref(props.initialPage ?? 1)
const isLoading = ref(false)

// Computed
const filteredUsers = computed(() => {
  return props.users.filter((user) =>
    user.name.toLowerCase().includes(searchQuery.value.toLowerCase()),
  )
})

const paginatedUsers = computed(() => {
  const start = (currentPage.value - 1) * PAGINATION_LIMIT
  return filteredUsers.value.slice(start, start + PAGINATION_LIMIT)
})

// Methods
const handleUserClick = (user: User) => {
  emit("user-selected", user)
}

const fetchUserDetails = async (userId: number) => {
  isLoading.value = true
  try {
    await userStore.fetchUserDetails(userId)
  } finally {
    isLoading.value = false
  }
}

// Watchers
watch(currentPage, (newPage) => {
  emit("update:page", newPage)
  router.push({ query: { page: newPage.toString() } })
})

watchEffect(() => {
  document.title = `Users (${filteredUsers.value.length})`
})

// Lifecycle Hooks
onMounted(() => {
  fetchUserDetails(props.users[0].id)
})
</script>

<style scoped>
.users-list {
  padding: 1rem;
}

.loading {
  color: #666;
}
</style>
```

## Additional Best Practices

1. **Type Safety**
   - Use TypeScript whenever possible
   - Define proper interfaces/types for props and events
   - Use type inference where appropriate

2. **Naming Conventions**
   - Use PascalCase for component names
   - Use camelCase for ref/reactive variables
   - Prefix boolean variables with `is`, `has`, or `should`
   - Prefix event handlers with `handle` or `on`

3. **File Organization**
   - One component per file
   - Use meaningful file names that match component names
   - Group related components in subdirectories

4. **Props**
   - Always define prop types
   - Use required props when necessary
   - Provide default values when appropriate
   - Document complex props with comments

5. **Events**
   - Use kebab-case for event names
   - Prefix v-model events with 'update:'
   - Document event payloads with TypeScript types

6. **Performance**
   - Use `shallowRef` for large objects when deep reactivity isn't needed
   - Use `computed` properties instead of methods for derived state
   - Avoid unnecessary watchers
   - Use `v-once` for static content

7. **Error Handling**
   - Always handle async errors
   - Provide meaningful error states in the UI
   - Use error boundaries where appropriate

8. **Testing**
   - Write unit tests for complex computed properties
   - Test component events and user interactions
   - Mock external dependencies
   - Test error states and edge cases
