API de la réactivité : Avancé
shallowRef()
Version partiellement réactive de ref()
.
Type :
tsfunction shallowRef<T>(value: T): ShallowRef<T> interface ShallowRef<T> { value: T }
Détails
Contrairement à
ref()
, la valeur interne d'une ref partiellement réactive est stockée et exposée telle quelle, et ne sera pas rendue profondément réactive. Seul l'accès.value
est réactif.shallowRef()
est généralement utilisée pour l'optimisation des performances de grandes structures de données ou l'intégration avec des systèmes de gestion d'état externes.Exemple
jsconst state = shallowRef({ count: 1 }) // ne déclenche PAS de changement state.value.count = 2 // déclenche un changement state.value = { count: 2 }
Voir aussi
triggerRef()
Force le déclenchement d'effets qui dépendent d'une ref partiellement réactive. Ceci est généralement utilisé après avoir effectué des mutations profondes sur la valeur interne d'une ref partiellement réactive.
Type :
tsfunction triggerRef(ref: ShallowRef): void
Exemple
jsconst shallow = shallowRef({ greet: 'Hello, world' }) // Logue "Hello, world" une fois pour la première exécution watchEffect(() => { console.log(shallow.value.greet) }) // Cela ne déclenchera pas l'effet car la ref est partiellement réactive shallow.value.greet = 'Hello, universe' // Logue "Hello, universe" triggerRef(shallow)
customRef()
Crée une ref personnalisée avec un contrôle explicite sur son suivi des dépendances et le déclenchement des mises à jour.
Type :
tsfunction customRef<T>(factory: CustomRefFactory<T>): Ref<T> type CustomRefFactory<T> = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void }
Détails
customRef()
attend une fonction factory, qui reçoit les fonctionstrack
ettrigger
comme arguments et doit renvoyer un objet avec les méthodesget
etset
.En général,
track()
doit être appelée à l'intérieur deget()
, ettrigger()
doit être appelée à l'intérieur deset()
. Cependant, vous avez un contrôle total sur le moment où elles doivent être appelées.Exemple
Création d'une ref debounced qui ne met à jour la valeur qu'après un certain délai après le dernier appel défini :
jsimport { customRef } from 'vue' export function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) }
Utilisation dans un composant :
vue<script setup> import { useDebouncedRef } from './debouncedRef' const text = useDebouncedRef('hello') </script> <template> <input v-model="text" /> </template>
À utiliser avec précaution
Lorsque l'on utilise une ref personnalisée, il convient d'être prudent quant à la valeur de retour de son accesseur, en particulier lorsque l'on génère de nouveaux types de données d'objets à chaque fois que le getter est exécuté. Cela affecte la relation entre les composants parent et enfant, lorsqu'une ref a été transmise en tant que prop.
La fonction de rendu du composant parent pourrait être déclenchée par des changements dans un état réactif différent. Pendant le rendu, la valeur de notre ref personnalisée est réévaluée, renvoyant un nouveau type de données d'objet en tant que prop à un composant enfant. Cette prop est comparé à sa dernière valeur dans le composant enfant, et comme ils sont différents, les dépendances réactives de la ref personnalisée sont déclenchées dans le composant enfant. Pendant ce temps, les dépendances réactives du composant parent ne s'exécutent pas car le mutateur de la ref n'a pas été appelé et ses dépendances n'ont pas été déclenchées en conséquence.
Use with caution
When using customRef, we should be cautious about the return value of its getter, particularly when generating new object datatypes each time the getter is run. This affects the relationship between parent and child components, where such a customRef has been passed as a prop.
The parent component's render function could be triggered by changes to a different reactive state. During rerender, the value of our customRef is reevaluated, returning a new object datatype as a prop to a child component. This prop is compared with its last value in the child component, and since they are different, the reactive dependencies of the customRef are triggered in the child component. Meanwhile, the reactive dependencies in the parent component do not run because the customRef's setter was not called, and its dependencies were not triggered as a result.
shallowReactive()
Version partiellement réactive de reactive()
.
Type :
tsfunction shallowReactive<T extends object>(target: T): T
Détails
Contrairement à
reactive()
, il n'y a pas de conversion profonde : seules les propriétés de niveau racine sont réactives pour un objet partiellement réactif. Les valeurs de propriété sont stockées et exposées telles quelles - cela signifie également que les propriétés avec des valeurs de ref ne seront pas automatiquement déballées.À utiliser avec précaution
Les structures de données partiellement réactives ne doivent être utilisées que pour l'état de niveau racine dans un composant. Évitez de l'imbriquer dans un objet réactif profond car cela crée un arbre avec un comportement de réactivité incohérent qui peut être difficile à comprendre et à déboguer.
Exemple
jsconst state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // muter les propriétés propres de l'état est réactif state.foo++ // ...mais ne convertit pas les objets imbriqués isReactive(state.nested) // false // PAS réactif state.nested.bar++
shallowReadonly()
Version partiellement réactive de readonly()
.
Type :
tsfunction shallowReadonly<T extends object>(target: T): Readonly<T>
Détails
Contrairement à
readonly()
, il n'y a pas de conversion profonde : seules les propriétés de niveau racine sont en lecture seule. Les valeurs de propriété sont stockées et exposées telles quelles - cela signifie également que les propriétés avec des valeurs de ref ne seront pas automatiquement déballées.À utiliser avec précaution
Les structures de données partiellement réactives ne doivent être utilisées que pour l'état de niveau racine dans un composant. Évitez de l'imbriquer dans un objet réactif profond car cela crée un arbre avec un comportement de réactivité incohérent qui peut être difficile à comprendre et à déboguer.
Exemple
jsconst state = shallowReadonly({ foo: 1, nested: { bar: 2 } }) // muter les propriétés propres de l'état va échouer state.foo++ // ...mais fonctionne sur des objets imbriqués isReadonly(state.nested) // false // fonctione state.nested.bar++
toRaw()
Renvoie l'objet brut d'origine d'un proxy créé par Vue.
Type :
tsfunction toRaw<T>(proxy: T): T
Détails
toRaw()
peut renvoyer l'objet d'origine à partir de proxys créés parreactive()
,readonly()
,shallowReactive()
oushallowReadonly()
.Il s'agit d'une solution d'échappement qui peut être utilisée pour lire temporairement sans encourir d'accès au proxy / de surcharge de suivi ou pour écrire sans déclencher de modifications. Il n'est pas recommandé de conserver une ref persistante à l'objet d'origine. À utiliser avec précaution.
Exemple
jsconst foo = {} const reactiveFoo = reactive(foo) console.log(toRaw(reactiveFoo) === foo) // true
markRaw()
Marque un objet afin qu'il ne soit jamais converti en proxy. Renvoie l'objet lui-même.
Type :
tsfunction markRaw<T extends object>(value: T): T
Exemple
jsconst foo = markRaw({}) console.log(isReactive(reactive(foo))) // false // fonctionne également lorsqu'il est imbriqué dans d'autres objets réactifs const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false
À utiliser avec précaution
markRaw()
et les API partiellement réactives telles queshallowReactive()
vous permettent de désactiver de manière sélective la conversion profonde réactive/lecture seule par défaut et d'intégrer des objets bruts sans proxy dans votre graphe d'état. Elles peuvent être utilisées pour diverses raisons :Certaines valeurs ne doivent tout simplement pas être rendues réactives, par exemple une instance de classe tierce complexe ou un objet de composant Vue.
Ignorer la conversion proxy peut améliorer les performances lors du rendu de grandes listes avec des sources de données immuables.
Elles sont considérées comme avancées car l'objet brut n'est défini qu'au niveau racine, donc si vous définissez un objet brut imbriqué et non marqué comme brut dans un objet réactif, puis y accédez à nouveau, vous récupérez la version proxyfiée. Cela peut entraîner des risques d'identité - par exemple effectuer une opération qui repose sur l'identité de l'objet mais en utilisant à la fois la version brute et la version proxyfiée du même objet :
jsconst foo = markRaw({ nested: {} }) const bar = reactive({ // bien que `foo` soit marqué comme brut, foo.nested ne l'est pas. nested: foo.nested }) console.log(foo.nested === bar.nested) // false
Les risques d'identité sont en général rares. Cependant, pour utiliser correctement ces API tout en évitant en toute sécurité les risques d'identité, il faut une solide compréhension du fonctionnement du système de réactivité.
effectScope()
Crée un objet de portée d'effet qui peut capturer les effets réactifs (c'est-à-dire les propriétés calculées et les observateurs) créés en son sein afin que ces effets puissent être disposés. Pour des cas d'utilisation détaillés de cette API, veuillez consulter son RFC correspondant.
Type :
tsfunction effectScope(detached?: boolean): EffectScope interface EffectScope { run<T>(fn: () => T): T | undefined // undefined si le scope est inactif stop(): void }
Exemple
jsconst scope = effectScope() scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, () => console.log(doubled.value)) watchEffect(() => console.log('Count: ', doubled.value)) }) // pour disposer tous les effets du scope scope.stop()
getCurrentScope()
Renvoie la portée d'effet active actuelle s'il y en a une.
Type :
tsfunction getCurrentScope(): EffectScope | undefined
onScopeDispose()
Enregistre une fonction de suppression sur la portée d'effet active actuelle. La fonction sera appelée lorsque la portée d'effet associée sera arrêtée.
Cette méthode peut être utilisée comme remplacement non couplé à un composant de onUnmount
dans les fonctions de composition réutilisables, puisque la fonction setup()
de chaque composant Vue est également invoquée dans une portée d'effet.
Un avertissement sera levé si la fonction est appelée sans d'effect scope actif. À partir de la version 3.5, cet avertissement peut être désactivé en passant tre
au second argument.
Type :
tsfunction onScopeDispose(fn: () => void, failSilently?: boolean): void