289 lines
6.1 KiB
Markdown
289 lines
6.1 KiB
Markdown
1. Organize Your Code into Logical Sections
|
||
|
||
Structure your component script into clear sections to improve readability. A common approach is to group related logic together.
|
||
Example Structure:
|
||
|
||
<script setup>
|
||
// 1. Imports
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
|
||
// 2. Reactive State
|
||
const count = ref(0)
|
||
const name = ref('')
|
||
|
||
// 3. Computed Properties
|
||
const doubledCount = computed(() => count.value * 2)
|
||
|
||
// 4. Functions / Methods
|
||
function increment() {
|
||
count.value++
|
||
}
|
||
|
||
// 5. Lifecycle Hooks
|
||
onMounted(() => {
|
||
console.log('Component mounted')
|
||
})
|
||
|
||
// 6. Watchers
|
||
watch(count, (newValue, oldValue) => {
|
||
console.log(`Count changed from ${oldValue} to ${newValue}`)
|
||
})
|
||
</script>
|
||
|
||
---
|
||
|
||
2. Use script setup Syntax
|
||
|
||
The <script setup> syntax is the recommended way to write Composition API components. It provides a more concise and intuitive syntax.
|
||
Example:
|
||
|
||
<script setup>
|
||
const message = ref('Hello, Vue 3!')
|
||
</script>
|
||
|
||
<template>
|
||
<p>{{ message }}</p>
|
||
</template>
|
||
|
||
---
|
||
|
||
3. Use Descriptive Variable and Function Names
|
||
|
||
Choose meaningful names for variables, functions, and computed properties to make your code self-documenting.
|
||
Example:
|
||
// Bad
|
||
const x = ref(0)
|
||
|
||
// Good
|
||
const userCount = ref(0)
|
||
|
||
---
|
||
|
||
4. Extract Reusable Logic into Composables
|
||
Move reusable logic into composables (custom hooks) to keep your components clean and promote code reuse.
|
||
Example Composable:
|
||
|
||
// composables/useCounter.js
|
||
import { ref } from 'vue'
|
||
|
||
export function useCounter(initialValue = 0) {
|
||
const count = ref(initialValue)
|
||
|
||
function increment() {
|
||
count.value++
|
||
}
|
||
|
||
function reset() {
|
||
count.value = initialValue
|
||
}
|
||
|
||
return {
|
||
count,
|
||
increment,
|
||
reset,
|
||
}
|
||
}
|
||
|
||
Usage in a Component:
|
||
|
||
<script setup>
|
||
import { useCounter } from '~/composables/useCounter'
|
||
|
||
const { count, increment } = useCounter()
|
||
</script>
|
||
|
||
<template>
|
||
<p>Count: {{ count }}</p>
|
||
<button @click="increment">Increment</button>
|
||
</template>
|
||
|
||
---
|
||
|
||
5. Use ref for Primitive Values and reactive for Objects
|
||
|
||
- Use ref for primitive values (e.g., numbers, strings, booleans).
|
||
- Use reactive for objects or arrays.
|
||
|
||
Example:
|
||
const count = ref(0) // Primitive value
|
||
const user = reactive({ name: 'John', age: 30 }) // Object
|
||
|
||
---
|
||
|
||
6. Use Computed Properties for Derived State
|
||
|
||
Use computed to create reactive properties that depend on other state. This ensures the derived state is always up-to-date.
|
||
Example:
|
||
const firstName = ref('John')
|
||
const lastName = ref('Doe')
|
||
|
||
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
||
|
||
---
|
||
|
||
7. Use Watchers Sparingly
|
||
|
||
Watchers (watch and watchEffect) are powerful but can make your code harder to understand if overused. Prefer computed properties or event-driven updates where possible.
|
||
Example:
|
||
watch(count, (newValue, oldValue) => {
|
||
console.log(`Count changed from ${oldValue} to ${newValue}`)
|
||
})
|
||
|
||
---
|
||
|
||
8. Group Related Logic Together
|
||
|
||
Keep related reactive state, computed properties, and functions together to make your code easier to follow.
|
||
Example:
|
||
// User-related logic
|
||
const user = reactive({ name: 'John', age: 30 })
|
||
const isAdult = computed(() => user.age >= 18)
|
||
function updateUser(newName) {
|
||
user.name = newName
|
||
}
|
||
|
||
-----------
|
||
|
||
9. Use Lifecycle Hooks for Side Effects
|
||
|
||
Use lifecycle hooks (onMounted, onUnmounted, etc.) for side effects like fetching data or setting up event listeners.
|
||
Example:
|
||
onMounted(() => {
|
||
console.log('Component mounted')
|
||
fetchData()
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
console.log('Component unmounted')
|
||
cleanup()
|
||
})
|
||
|
||
----------------
|
||
|
||
10. Use TypeScript for Better Type Safety
|
||
If your project uses TypeScript, leverage it to add type safety to your components.
|
||
Example:
|
||
<script setup lang="ts">
|
||
interface User {
|
||
name: string
|
||
age: number
|
||
}
|
||
|
||
const user = ref<User>({ name: 'John', age: 30 })
|
||
</script>
|
||
|
||
--------------
|
||
|
||
11. Keep Templates Clean
|
||
|
||
Avoid putting too much logic in your template. Instead, move complex logic into the script or composables.
|
||
Example:
|
||
<template>
|
||
<div>
|
||
<p>{{ fullName }}</p>
|
||
<button @click="increment">Increment</button>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
const firstName = ref('John')
|
||
const lastName = ref('Doe')
|
||
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
||
|
||
function increment() {
|
||
// Logic here
|
||
}
|
||
</script>
|
||
|
||
------------
|
||
|
||
12. Use provide and inject for Prop Drilling
|
||
Avoid prop drilling by using provide and inject to share state across deeply nested components.
|
||
Example:
|
||
// Parent component
|
||
import { provide, ref } from 'vue'
|
||
|
||
const theme = ref('dark')
|
||
provide('theme', theme)
|
||
|
||
// Child component
|
||
import { inject } from 'vue'
|
||
|
||
const theme = inject('theme')
|
||
|
||
-----------------
|
||
|
||
13. Use v-model for Two-Way Binding
|
||
|
||
Use v-model to simplify two-way binding between parent and child components.
|
||
Example:
|
||
<!-- Parent component -->
|
||
<template>
|
||
<ChildComponent v-model:name="userName" />
|
||
</template>
|
||
|
||
<script setup>
|
||
const userName = ref('John')
|
||
</script>
|
||
|
||
<!-- Child component -->
|
||
<template>
|
||
<input :value="name" @input="$emit('update:name', $event.target.value)" />
|
||
</template>
|
||
|
||
<script setup>
|
||
defineProps(['name'])
|
||
defineEmits(['update:name'])
|
||
</script>
|
||
|
||
----------
|
||
|
||
14. Use defineProps and defineEmits for TypeScript Support
|
||
|
||
When using TypeScript, use defineProps and defineEmits to define props and emits with type safety.
|
||
Example:
|
||
<script setup lang="ts">
|
||
const props = defineProps<{
|
||
title: string
|
||
count: number
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
(event: 'update:count', value: number): void
|
||
}>()
|
||
</script>
|
||
|
||
-------------
|
||
|
||
15. Use Scoped Styles
|
||
|
||
Use scoped styles (<style scoped>) to ensure styles are component-specific and don’t leak into other components.
|
||
Example:
|
||
<style scoped>
|
||
.button {
|
||
background-color: blue;
|
||
}
|
||
</style>
|
||
|
||
------------------
|
||
|
||
16. Use Environment Variables
|
||
|
||
Use environment variables for configuration (e.g., API URLs) to keep your code flexible and secure.
|
||
Example:
|
||
const apiUrl = import.meta.env.VITE_API_URL
|
||
|
||
-------------
|
||
|
||
17. Write Unit Tests
|
||
|
||
Write unit tests for your components and composables to ensure they work as expected.
|
||
Example:
|
||
import { render } from '@testing-library/vue'
|
||
import MyComponent from '@/components/MyComponent.vue'
|
||
|
||
test('renders correctly', () => {
|
||
const { getByText } = render(MyComponent)
|
||
expect(getByText('Hello, Vue 3!')).toBeInTheDocument()
|
||
}) |