Skip to content
← Todas las preguntas
Avanzado

¿Cómo funcionan las propiedades computed con escritura?

Reactividad

Una propiedad computed normal es de solo lectura: deriva un valor de las dependencias reactivas. Un computed con escritura añade un setter, por lo que puedes asignarle un valor y el setter actualiza los datos fuente subyacentes.

Ejemplo básico

ts
import { ref, computed } from 'vue'

const firstName = ref('Ana')
const lastName = ref('García')

const fullName = computed({
  get: () => `${firstName.value} ${lastName.value}`,
  set: (value: string) => {
    const [first, ...rest] = value.split(' ')
    firstName.value = first
    lastName.value = rest.join(' ')
  }
})

console.log(fullName.value) // "Ana García"

fullName.value = 'Luis Fernández'
console.log(firstName.value) // "Luis"
console.log(lastName.value)  // "Fernández"

El getter deriva el valor. El setter descompone el valor asignado de vuelta en los refs fuente.

Con v-model

Las propiedades computed con escritura son útiles para vincular v-model a un valor derivado:

vue
<script setup>
import { ref, computed } from 'vue'

const price = ref(100)
const taxRate = ref(0.21)

const priceWithTax = computed({
  get: () => price.value * (1 + taxRate.value),
  set: (total: number) => {
    price.value = total / (1 + taxRate.value)
  }
})
</script>

<template>
  <label>
    Price (with tax):
    <input v-model.number="priceWithTax" type="number" />
  </label>
  <p>Base price: {{ price.toFixed(2) }}</p>
</template>

El usuario edita el total y el setter calcula el precio base.

Patrón de formateo

Convierte entre el formato de visualización y el formato almacenado:

ts
const dateRaw = ref('2024-03-15')

const dateFormatted = computed({
  get: () => {
    const [y, m, d] = dateRaw.value.split('-')
    return `${d}/${m}/${y}`
  },
  set: (display: string) => {
    const [d, m, y] = display.split('/')
    dateRaw.value = `${y}-${m}-${d}`
  }
})

// dateFormatted.value → "15/03/2024"
// dateFormatted.value = "20/06/2024" → dateRaw se convierte en "2024-06-20"

Proxy para el estado de un store

Cuando necesitas v-model en un valor de un store de Pinia:

ts
import { computed } from 'vue'
import { useSettingsStore } from '@/stores/settings'

const store = useSettingsStore()

const theme = computed({
  get: () => store.theme,
  set: (value: string) => store.setTheme(value)
})
vue
<template>
  <select v-model="theme">
    <option value="light">Light</option>
    <option value="dark">Dark</option>
  </select>
</template>

Reglas

  • El setter debe actualizar las fuentes que lee el getter. Si no lo hace, el valor computed quedará desactualizado.
  • No realices operaciones asíncronas ni efectos secundarios en los getters. Los setters pueden activar efectos secundarios (como acciones del store) ya que se invocan explícitamente.
  • Si te encuentras escribiendo lógica compleja en el setter, considera si un método o un watcher sería más claro.

Cuándo usar computed con escritura

Escenario¿Computed con escritura?
v-model en un valor derivado o formateado
Binding bidireccional a una propiedad del store
Conversión de unidades (km/millas, C/F)
Transformación compleja de varios pasosProbablemente no, usa un método
Operaciones asíncronas en el setNo, usa un watcher

Ver también: ¿Cuál es la diferencia entre computed y watch? · ¿Cuál es la diferencia entre ref y reactive?

Referencias

Publicado bajo la licencia MIT.