Les composables Vue sont incroyablement puissants, mais ils peuvent rapidement devenir compliqués et difficiles à maintenir si vous ne faites pas attention.
C'est pourquoi j'ai identifié 13 conseils qui vous aideront à écrire des composables meilleurs et plus maintenables.
Que vous construisiez une solution simple de gestion d'état ou une logique partagée complexe, ces conseils vous aideront :
Les conseils que vous apprendrez sont :
Plongeons dans chaque modèle et voyons comment ils peuvent améliorer vos applications Vue.
Et n'oubliez pas de commenter ci-dessous avec votre astuce préférée !
Le modèle de magasin de données peut aider à éviter de transmettre des accessoires et des événements à travers plusieurs couches de composants.
Une situation est celle où vous avez un parent et un enfant qui communiquent à travers des forages d'accessoires sans fin et des bouillonnements d'événements :
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
Cela crée beaucoup de complexité puisque ces accessoires et événements doivent se déplacer dans la hiérarchie des composants.
Une solution plus simple consiste à créer un magasin de données partagé que n'importe quel composant peut importer :
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
Le modèle de magasin de données est également utile lorsque des composants frères ou « cousins » doivent partager les mêmes données sans aucune connexion directe.
Supposons que deux frères et sœurs nécessitent tous deux le même objet utilisateur, mais qu'il n'y a pas de chemin élégant pour les accessoires ou les événements.
Cela entraîne souvent des données difficiles à jongler entre un état parent ou dupliqué.
Une meilleure approche consiste à s'appuyer sur un seul magasin composable que les deux frères et sœurs peuvent consommer :
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
Le modèle de magasin de données encourage à fournir des méthodes claires pour mettre à jour l'état partagé.
Certains développeurs exposent l'intégralité de l'objet réactif au monde, comme ceci :
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
Cela permet à n'importe qui de modifier la propriété darkMode de l'utilisateur directement à partir de n'importe quel fichier, ce qui peut conduire à des mutations dispersées et incontrôlées.
Une meilleure idée est de renvoyer l'état en lecture seule avec des fonctions qui définissent comment les mises à jour se produisent :
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
Le modèle Composables en ligne permet de diviser les composants volumineux en rassemblant l'état et la logique associés en fonctions plus petites.
Un composant géant pourrait mettre toutes ses références et méthodes au même endroit :
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
Cette configuration devient rapidement ingérable.
Au lieu de cela, un composable en ligne peut regrouper la logique et la fournir localement. Nous pourrons ensuite l'extraire dans un fichier séparé ultérieurement :
export const user = reactive({ darkMode: false })
Le modèle Thin Composables nous demande de séparer la logique métier brute de la réactivité de Vue afin que les tests et la maintenance deviennent plus simples.
Vous pouvez intégrer toute la logique dans le composable :
import { reactive, readonly } from 'vue' const state = reactive({ darkMode: false }) export function toggleDarkMode() { state.darkMode = !state.darkMode } export function useUserStore() { return { darkMode: readonly(state.darkMode), toggleDarkMode } }
Cela vous oblige à tester la logique dans un environnement Vue.
Au lieu de cela, conservez les règles compliquées dans des fonctions pures et laissez le composable gérer uniquement les wrappers réactifs :
<script setup> const count = ref(0) const user = ref({ name: 'Alice' }) // 500 more lines of intertwined code with watchers, methods, etc. </script>
Le modèle Async Sync Composables fusionne les comportements synchrones et asynchrones en un seul composable au lieu de créer des fonctions distinctes.
C'est exactement comme le fonctionnement de useAsyncData de Nuxt.
Nous avons ici un seul composable qui peut renvoyer une promesse tout en donnant également des propriétés réactives immédiates pour une utilisation synchrone :
<script setup> function useCounter() { const count = ref(0) const increment = () => count.value++ return { count, increment } } const { count, increment } = useCounter() </script>
Le modèle d'objet Options peut effacer de longues listes de paramètres en attendant un seul objet de configuration.
Les appels comme celui-ci sont fastidieux et sujets aux erreurs, et l'ajout de nouvelles options nécessite la mise à jour de la signature de la fonction :
export function useCounter() { const count = ref(0) function increment() { count.value = (count.value * 3) / 2 } return { count, increment } }
La signification de chaque argument n’est pas évidente.
Un composable qui accepte un objet options garde tout descriptif :
// counterLogic.js export function incrementCount(num) { return (num * 3) / 2 } // useCounter.js import { ref } from 'vue' import { incrementCount } from './counterLogic' export function useCounter() { const count = ref(0) function increment() { count.value = incrementCount(count.value) } return { count, increment } }
Le modèle d'objet Options recommande également des valeurs par défaut pour chaque propriété.
Une fonction qui suppose que certains champs existent peut être problématique s'ils ne sont pas transmis :
import { ref } from 'vue' export function useAsyncOrSync() { const data = ref(null) const promise = fetch('/api') .then(res => res.json()) .then(json => { data.value = json return { data } }) return Object.assign(promise, { data }) }
Il est préférable de déstructurer les options avec des valeurs par défaut sûres :
useRefHistory(someRef, true, 10, 500, 'click', false)
Le modèle de retour dynamique garantit qu'un composable peut renvoyer soit une valeur unique pour des cas d'utilisation simples, soit un objet étendu avec des contrôles plus avancés.
Certaines approches renvoient toujours un objet avec tout :
<!-- Parent.vue --> <template> <!-- But many more layers of components --> <Child :user="user" @change="onUserChange" /> </template> <script setup> const user = ref({ name: 'Alice' }) function onUserChange(updatedUser) { user.value = updatedUser } </script>
Quiconque n'a besoin que de la valeur réactive principale est obligé de gérer des éléments supplémentaires.
Un composable qui renvoie conditionnellement une seule référence ou un objet résout cela :
import { reactive, toRefs } from 'vue' const state = reactive({ user: { name: 'Alice' } }) export function useUserStore() { return toRefs(state) }
Le modèle Composables cachés permet d'éviter de mélanger des logiques mutuellement exclusives dans le même composable.
Certains codes regroupent plusieurs modes ou chemins de code :
// SiblingA.vue import { useUserStore } from './useUserStore' const { user } = useUserStore() // SiblingB.vue import { useUserStore } from './useUserStore' const { user } = useUserStore()
Diviser chaque chemin en son propre composable est beaucoup plus clair et n'affecte pas la fonctionnalité :
export const user = reactive({ darkMode: false })
Le modèle d'arguments flexibles garantit que les entrées et les sorties des composables sont traitées uniformément comme des données réactives ou des valeurs brutes, évitant ainsi toute confusion.
Certains codes vérifient si une entrée est une référence ou non :
import { reactive, readonly } from 'vue' const state = reactive({ darkMode: false }) export function toggleDarkMode() { state.darkMode = !state.darkMode } export function useUserStore() { return { darkMode: readonly(state.darkMode), toggleDarkMode } }
Au lieu de cela, vous pouvez convertir immédiatement.
En utilisant ref, si l'entrée est une référence, cette référence sera renvoyée. Sinon, il sera converti en réf :
<script setup> const count = ref(0) const user = ref({ name: 'Alice' }) // 500 more lines of intertwined code with watchers, methods, etc. </script>
Le modèle d'arguments flexibles utilise également toValue lorsqu'un déballage est nécessaire.
Sans cela, le code pourrait continuer à effectuer des vérifications isRef :
<script setup> function useCounter() { const count = ref(0) const increment = () => count.value++ return { count, increment } } const { count, increment } = useCounter() </script>
C'est beaucoup plus simple d'appeler :
export function useCounter() { const count = ref(0) function increment() { count.value = (count.value * 3) / 2 } return { count, increment } }
Le modèle Options to Composition vous permet de migrer les gros composants de l'API Options vers l'API Composition étape par étape, de manière incrémentielle et facile à suivre.
Un composant Options classique pourrait faire ceci :
// counterLogic.js export function incrementCount(num) { return (num * 3) / 2 } // useCounter.js import { ref } from 'vue' import { incrementCount } from './counterLogic' export function useCounter() { const count = ref(0) function increment() { count.value = incrementCount(count.value) } return { count, increment } }
Les données, les propriétés calculées et les méthodes sont dispersées.
Le convertir en configuration de script les rassemble et facilite le suivi, et vous permet d'utiliser ces modèles :
import { ref } from 'vue' export function useAsyncOrSync() { const data = ref(null) const promise = fetch('/api') .then(res => res.json()) .then(json => { data.value = json return { data } }) return Object.assign(promise, { data }) }
Ces 13 conseils vous aideront à écrire de meilleurs composables Vue, plus faciles à maintenir, à tester et à réutiliser dans vos applications.
Mais nous ne faisons qu'effleurer la surface ici.
Au fil des années, j'ai rassemblé bien d'autres modèles et astuces, et je les ai tous intégrés dans un cours approfondi sur les modèles composables.
Il couvre 16 modèles au total, et chaque modèle a :
Allez ici pour en savoir plus.
Oh, et ce cours est en vente jusqu'au 15 janvier, vous pouvez donc l'obtenir à un prix avantageux dès maintenant !
Découvrez les modèles de conception composables
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!