Reactividad: Núcleo (Core)
Véase también
Para comprender mejor las API de Reactividad, se recomienda leer los siguientes capítulos de la guía:
- Fundamentos de Reactividad (con la preferencia de API establecida en Composition API)
- Reactividad en Profundidad
ref()
Toma un valor interno y devuelve un objeto ref reactivo y mutable, que tiene una sola propiedad .value
que apunta al valor interno.
Tipo
tsfunction ref<T>(value: T): Ref<UnwrapRef<T>> interface Ref<T> { value: T }
Detalles
El objeto ref es mutable, es decir, puedes asignar nuevos valores a
.value
. También es reactivo, es decir, se rastrea cualquier operación de lectura a.value
, y las operaciones de escritura activarán los efectos asociados.Si se asigna un objeto como valor de una ref, el objeto se vuelve profundamente reactivo con reactive(). Esto también significa que si el objeto contiene refs anidadas, se desenvolverán profundamente.
Para evitar la conversión profunda, utilice
shallowRef()
en su lugar.Ejemplo
jsconst count = ref(0) console.log(count.value) // 0 count.value = 1 console.log(count.value) // 1
Véase también
computed()
Toma una función getter y devuelve un objeto ref reactivo de solo lectura para el valor devuelto por el getter. También puede tomar un objeto con funciones get
y set
para crear un objeto ref escribible.
Tipo
ts// solo lectura function computed<T>( getter: (oldValue: T | undefined) => T, // véase el enlace "Depuración de Computed" más abajo debuggerOptions?: DebuggerOptions ): Readonly<Ref<Readonly<T>>> // escribible function computed<T>( options: { get: (oldValue: T | undefined) => T set: (value: T) => void }, debuggerOptions?: DebuggerOptions ): Ref<T>
Ejemplo
Creando una ref calculada de solo lectura:
jsconst count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error
Creando una ref calculada escribible:
jsconst count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
Depuración:
jsconst plusOne = computed(() => count.value + 1, { onTrack(e) { debugger }, onTrigger(e) { debugger } })
Véase también
reactive()
Devuelve un proxy reactivo del objeto.
Tipo
tsfunction reactive<T extends object>(target: T): UnwrapNestedRefs<T>
Detalles
La conversión reactiva es "profunda": afecta a todas las propiedades anidadas. Un objeto reactivo también desenvuelve profundamente cualquier propiedad que sea refs mientras mantiene la reactividad.
También se debe tener en cuenta que no se desenvuelve la ref cuando se accede a la ref como un elemento de un array reactivo o de un tipo de colección nativa como
Map
.Para evitar la conversión profunda y solo retener la reactividad en el nivel raíz, utiliza en su lugar shallowReactive().
El objeto devuelto y sus objetos anidados están envueltos con ES Proxy y no son iguales a los objetos originales. Se recomienda trabajar exclusivamente con el proxy reactivo y evitar depender del objeto original.
Ejemplo
Creando un objeto reactivo:
jsconst obj = reactive({ count: 0 }) obj.count++
Desenvolvimiento de la ref:
tsconst count = ref(1) const obj = reactive({ count }) // ref será desenvuelto console.log(obj.count === count.value) // true // se actualizará `obj.count` count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // también actualizará la ref `count`. obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3
Tenga en cuenta que las refs no se desenvuelven cuando se accede a ellas como elementos de un array o de una colección:
jsconst books = reactive([ref('Vue 3 Guide')]) // se necesita .value aquí console.log(books[0].value) const map = reactive(new Map([['count', ref(0)]])) // se necesita .value aquí console.log(map.get('count').value)
Al asignar una ref a una propiedad
reactive
, esa ref también se desenvolverá automáticamente:tsconst count = ref(1) const obj = reactive({}) obj.count = count console.log(obj.count) // 1 console.log(obj.count === count.value) // true
Véase también
readonly()
Toma un objeto (reactivo o simple) o una ref y devuelve un proxy de solo lectura del original.
Tipo
tsfunction readonly<T extends object>( target: T ): DeepReadonly<UnwrapNestedRefs<T>>
Detalles
Un proxy de solo lectura es profundo: cualquier propiedad anidada a la que se acceda también será de solo lectura. También tiene el mismo comportamiento de desenvolvimiento de refs que
reactive()
, excepto que los valores desenvueltos también se convertirán en solo lectura.Para evitar la conversión profunda, utiliza en su lugar shallowReadonly().
Ejemplo
jsconst original = reactive({ count: 0 }) const copy = readonly(original) watchEffect(() => { // funciona para el seguimiento de la reactividad console.log(copy.count) }) // La mutación del original activará los watchers que dependen de la copia original.count++ // La mutación de la copia fallará y dará lugar a una advertencia copy.count++ // advertencia!
watchEffect()
Ejecuta una función inmediatamente mientras realiza un seguimiento reactivo de sus dependencias y la vuelve a ejecutar cada vez que las dependencias cambian.
Tipo
tsfunction watchEffect( effect: (onCleanup: OnCleanup) => void, options?: WatchEffectOptions ): StopHandle type OnCleanup = (cleanupFn: () => void) => void interface WatchEffectOptions { flush?: 'pre' | 'post' | 'sync' // por defecto: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void } type StopHandle = () => void
Detalles
El primer argumento es la función de efecto que se ejecutará. La función de efecto recibe una función que se puede usar para registrar una devolución de llamada de limpieza. La devolución de llamada de limpieza se llamará justo antes de la próxima vez que se vuelva a ejecutar el efecto, y se puede usar para limpiar los efectos secundarios invalidados, por ejemplo, una petición asincrónica pendiente (ver ejemplo abajo).
El segundo argumento es un objeto de opciones opcional que se puede usar para ajustar el tiempo de descarga del efecto o para depurar las dependencias del efecto.
De forma predeterminada, los watchers se ejecutarán justo antes de la renderización del componente. Configurando
flush: 'post'
el watcher se aplazará hasta después de la renderización del componente. Consulta Temporización del Flujo del Callback para obtener más información. En casos excepcionales, podría ser necesario activar un watcher inmediatamente cuando cambia una dependencia reactiva, por ejemplo, para invalidar un caché. Esto se puede lograr usandoflush: 'sync'
. Sin embargo, esta configuración debe usarse con precaución, ya que puede provocar problemas con el rendimiento y la consistencia de los datos si se actualizan varias propiedades al mismo tiempo.El valor devuelto es una función de control que se puede llamar para evitar que el efecto se ejecute de nuevo.
Ejemplo
jsconst count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 count.value++ // -> logs 1
Limpieza de efectos secundarios:
jswatchEffect(async (onCleanup) => { const { response, cancel } = doAsyncWork(id.value) // Se llamará a `cancel` si cambia `id` // de modo que la solicitud pendiente anterior se cancelará // si aún no se ha completado onCleanup(cancel) data.value = await response })
Deteniendo el watcher:
jsconst stop = watchEffect(() => {}) // cuando el watcher ya no es necesario: stop()
Opciones:
jswatchEffect(() => {}, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
Véase también
watchPostEffect()
Alias de watchEffect()
con la opción flush: 'post'
.
watchSyncEffect()
Alias de watchEffect()
con la opción flush: 'sync'
.
watch()
Observa una o más fuentes de datos reactivas e invoca una función de devolución de llamada cuando las fuentes cambian.
Tipo
ts// observando una sola fuente function watch<T>( source: WatchSource<T>, callback: WatchCallback<T>, options?: WatchOptions ): StopHandle // observando multiples fuentes function watch<T>( sources: WatchSource<T>[], callback: WatchCallback<T[]>, options?: WatchOptions ): StopHandle type WatchCallback<T> = ( value: T, oldValue: T, onCleanup: (cleanupFn: () => void) => void ) => void type WatchSource<T> = | Ref<T> // ref | (() => T) // getter | T extends object ? T : never // objeto reactivo interface WatchOptions extends WatchEffectOptions { immediate?: boolean // por defecto: false deep?: boolean // por defecto: false flush?: 'pre' | 'post' | 'sync' // por defecto: 'pre' onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void once?: boolean // por defecto: false (3.4+) }
Los tipos se han simplificado para facilitar la lectura.
Detalles
watch()
es perezoso por defecto, es decir, la devolución de llamada solo se llama cuando la fuente observada ha cambiado.El primer argumento es la fuente del watcher. La fuente puede ser una de las siguientes:
- Una función getter que devuelve un valor
- Una ref
- Un objeto reactivo
- ... o un array de los anteriores.
El segundo argumento es la devolución de llamada que se llamará cuando la fuente cambie. La devolución de llamada recibe tres argumentos: el nuevo valor, el antiguo valor y una función para registrar una devolución de llamada de limpieza de efectos secundarios. La devolución de llamada de limpieza se llamará justo antes de la próxima vez que se vuelva a ejecutar el efecto, y se puede usar para limpiar los efectos secundarios invalidados, por ejemplo, una petición asíncrona pendiente.
Cuando se observan múltiples fuentes, la devolución de llamada recibe dos arreglos que contienen los valores nuevos/antiguos correspondientes al array de origen.
El tercer argumento opcional es un objeto de opciones que admite las siguientes opciones:
immediate
: activa la devolución de llamada inmediatamente después de la creación del watcher. El valor antiguo seráundefined
en la primera llamada.deep
: fuerza el recorrido profundo de la fuente si es un objeto, de modo que la devolución de llamada se dispare en mutaciones profundas. Vea Watchers Profundos.flush
: ajusta el tiempo de descarga de la devolución de llamada. Vea Temporización del Flujo del Callback ywatchEffect()
.onTrack / onTrigger
: depura las dependencias del watcher. Vea Depuración del Watcher.once
: ejecuta la devolución de llamada solo una vez. El observador se detiene automáticamente después de la primera ejecución de la devolución de llamada.
Comparado con
watchEffect()
,watch()
nos permite:- Realizar el efecto secundario de forma perezosa;
- Ser más específico sobre qué estado debe hacer que el watcher se vuelva a ejecutar;
- Acceder tanto al valor anterior como al actual del estado observado.
Ejemplo
Observando un getter:
jsconst state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
Observando una ref:
jsconst count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
Al observar múltiples fuentes, la devolución de llamada recibe arreglos que contienen valores nuevos/antiguos correspondientes al array de origen:
jswatch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
Cuando se utiliza una fuente getter, el watcher solo se activa si el valor de retorno del getter ha cambiado. Si deseas que la devolución de llamada se active incluso en mutaciones profundas, debes obligar explícitamente al watcher a entrar en modo profundo con
{ deep: true }
. Ten en cuenta que en el modo profundo, el nuevo valor y el antiguo valor serán el mismo objeto si la devolución de llamada se desencadenó por una mutación profunda:jsconst state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )
Cuando se observa directamente un objeto reactivo, el watcher está automáticamente en modo profundo:
jsconst state = reactive({ count: 0 }) watch(state, () => { /* desencadena una mutación profunda al estado */ })
watch()
comparte las mismas opciones de sincronización y depuración conwatchEffect()
:jswatch(source, callback, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
Detener el watcher:
jsconst stop = watch(source, callback) // cuando el watcher ya no es necesario: stop()
Limpieza de efectos secundarios:
jswatch(id, async (newId, oldId, onCleanup) => { const { response, cancel } = doAsyncWork(newId) // `cancel` será llamado si `id` cambia, cancelando // la petición anterior si aún no se ha completado onCleanup(cancel) data.value = await response })
Véase también