Skip to content

Reglas de Prioridad A: Esencial

Estas reglas ayudan a prevenir errores; apréndelas y apégate a ellas a toda costa. Pueden existir excepciones, pero deberían ser muy raras y solo las deben realizar por personas expertas tanto en JavaScript como en Vue.

Usar nombres de componentes de varias palabras

Los nombres de los componentes de usuario siempre deben tener varias palabras, excepto los componentes App raíz. Esto previene conflictos con elementos HTML existentes y futuros, ya que todos los elementos HTML tienen una sola palabra.

Incorrecto

template
<!-- en plantillas precompiladas -->
<Item />

<!-- en plantillas del DOM -->
<item></item>

Correcto

template
<!-- en plantillas precompiladas -->
<TodoItem />

<!-- en plantillas del DOM -->
<todo-item></todo-item>

Usar definiciones detalladas de las props

En el código comprometido, las definiciones de props siempre deberían ser lo más detalladas posible, especificando al menos los tipos.

Explicación detallada

Las definiciones detalladas de props tienen dos ventajas:

  • Documentan la API del componente, de modo que es fácil ver cómo se debe usar el componente.
  • En desarrollo, Vue te advertirá si proporcionas props con formato incorrecto a un componente, lo que te ayudará a detectar posibles fuentes de error.

Incorrecto

js
// Esto está bien solo cuando se crean prototipos
props: ['status']

Correcto

js
props: {
  status: String
}
js
// ¡Aún mejor!
props: {
  status: {
    type: String,
    required: true,

    validator: value => {
      return [
        'syncing',
        'synced',
        'version-conflict',
        'error'
      ].includes(value)
    }
  }
}

Incorrecto

js
// Esto está bien solo cuando se crean prototipos
const props = defineProps(['status'])

Correcto

js
const props = defineProps({
  status: String
})
js
// ¡Aún mejor!
const props = defineProps({
  status: {
    type: String,
    required: true,
    validator: (value) => {
      return ['syncing', 'synced', 'version-conflict', 'error'].includes(
        value
      )
    }
  }
})

Usar v-for con Clave

El uso de key con v-for siempre es necesaria en los componentes para mantener el estado interno del componente en el subárbol. Sin embargo, incluso para los elementos, es una buena práctica para mantener un comportamiento predecible, tal como la constancia del objeto en las animaciones.

Explicación detallada

Digamos que tienes una lista de ToDos:

js
data() {
  return {
    todos: [
      {
        id: 1,
        text: 'Aprender a usar v-for'
      },
      {
        id: 2,
        text: 'Aprender a usar key'
      }
    ]
  }
}
js
const todos = ref([
  {
    id: 1,
    text: 'Aprender a usar v-for'
  },
  {
    id: 2,
    text: 'Aprender a usar key'
  }
])

Luego los ordenas alfabéticamente. Al actualizar el DOM, Vue optimizará el renderizado para realizar las menor cantidad de mutaciones posibles del DOM. Eso podría significar eliminar el primer elemento de los ToDos y luego agregarlo nuevamente al final de la lista.

El problema es que hay casos en los que es importante no eliminar elementos que permanecerán en el DOM. Por ejemplo, es posible que desees utilizar <transition-group> para animar la ordenación de la lista o mantener el foco si el elemento renderizado es un <input>. En estos casos, agregar una key única para cada elemento (por ejemplo, :key="todo.id") le indicará a Vue cómo comportarse de manera más predecible.

Según nuestra experiencia, siempre es mejor agregar una key única, para que tu y tú equipo nuncan tengan que preocuparse por estos casos extremos. Luego, en los raros escenarios críticos para el rendimiento donde la constancia del objeto no es necesaria, puedes hacer una excepción consciente.

Incorrecto

template
<ul>
  <li v-for="todo in todos">
    {{ todo.text }}
  </li>
</ul>

Correcto

template
<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

Evitar usar v-if con v-for

Nunca utilices v-if en el mismo elemento que v-for.

Hay dos casos comunes en los que esto puede ser tentador:

  • Para filtrar elementos en una lista (por ejemplo, v-for="user in users" v-if="user.isActive"). En estos casos, reemplaza users con una nueva propiedad calculada que devuelva tu lista filtrada (por ejemplo, activeUsers).

  • Para evitar mostrar una lista, si debería estar oculta (por ejemplo, v-for="user in users" v-if="shouldShowUsers"). En estos casos, mueve el v-if a un elemento contenedor (p. ej., ul, ol).

Explicación detallada

Cuando Vue procesa directivas, v-if tiene mayor prioridad que v-for, por lo que esta plantilla:

template
<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

arrojará un error, porque la directiva v-if será evaluada primero y la variable de iteración user no existe en este momento.

Esto podría arreglarse iterando sobre una propiedad calculada, así:

js
computed: {
  activeUsers() {
    return this.users.filter(user => user.isActive)
  }
}
js
const activeUsers = computed(() => {
  return users.filter((user) => user.isActive)
})
template
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Alternativamente, podemos usar una etiqueta <template> con v-for para envolver el elemento <li>:

template
<ul>
  <template v-for="user in users" :key="user.id">
    <li v-if="user.isActive">
      {{ user.name }}
    </li>
  </template>
</ul>

Incorrecto

template
<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

Correcto

template
<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>
template
<ul>
  <template v-for="user in users" :key="user.id">
    <li v-if="user.isActive">
      {{ user.name }}
    </li>
  </template>
</ul>

Usar estilo de ámbito de componente

Para las aplicaciones, los estilos en un componente App de nivel superior y en los componentes layout pueden ser globales, pero todos los demás componentes deberían tener siempre un scope.

Esto solo es relevante para los Componentes de un Solo Archivo. No se requiere que uses el atributo scoped. El scope podría estar dado a través de módulos CSS, una estrategia basada en clases como BEM, u otra convención de alguna librería.

Las librerías de componentes, sin embargo, deberían preferir una estrategia basada en clases en lugar de usar el atributo scoped.

Esto facilita la sobreescritura de estilos internos con nombres de clases legibles por humanos que no tienen una especificidad demasiado alta, pero que es muy poco probable que generen conflicto.

Explicación detallada

Si estás desarrollando un proyecto grande, trabajando con otros desarrolladores o incluyendo HTML/CSS de terceros (por ejemplo, de Auth0), el scope coherente garantizará que tus estilos solo se apliquen a los componentes para los que están destinados.

Más allá del atributo scoped, el uso de nombres de clase únicos puede ayudar a garantizar que el CSS de terceros no se aplique a tu propio HTML. Por ejemplo, muchos proyectos usan los nombres de clase button, btn o icon, por lo que, incluso si no usas una estrategia como BEM, agregar un prefijo específico de la aplicación y/o del componente (por ejemplo, ButtonClose-icon) puede proporcionar cierta protección.

Incorrecto

template
<template>
  <button class="btn btn-close">×</button>
</template>

<style>
.btn-close {
  background-color: red;
}
</style>

Correcto

template
<template>
  <button class="button button-close">×</button>
</template>

<!-- Usando el atributo `scoped` -->
<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {
  background-color: red;
}
</style>
template
<template>
  <button :class="[$style.button, $style.buttonClose]">×</button>
</template>

<!-- Usando módulos CSS -->
<style module>
.button {
  border: none;
  border-radius: 2px;
}

.buttonClose {
  background-color: red;
}
</style>
template
<template>
  <button class="c-Button c-Button--close">×</button>
</template>

<!-- Usando la convención BEM -->
<style>
.c-Button {
  border: none;
  border-radius: 2px;
}

.c-Button--close {
  background-color: red;
}
</style>

Evitar exponer funciones privadas en mixins

Utiliza siempre el prefijo $_ para propiedades privadas personalizadas en un plugin, mixin, etc. que no deberían considerarse API públicas. Luego, para evitar conflictos con el código de otros autores, incluye también un scope con nombre (por ejemplo, $_yourPluginName_).

Explicación detallada

Vue usa el prefijo _ para definir sus propias propiedades privadas, por lo que usar el mismo prefijo (por ejemplo, _update) trae el riesgo de sobrescribir una propiedad de instancia. Incluso si marcas y Vue no está utilizando actualmente un nombre de propiedad en particular, no hay garantía de que no surja un conflicto en una versión posterior.

En cuanto al prefijo $, su propósito dentro del ecosistema Vue son las propiedades de instancias especiales que están expuestas al usuario, por lo que no sería apropiado usarlo para propiedades privadas.

En su lugar, recomendamos combinar los dos prefijos en $_, como una convención para las propiedades privadas definidas por el usuario para garantizar que no haya conflictos con Vue.

Incorrecto

js
const myGreatMixin = {
  // ...
  methods: {
    update() {
      // ...
    }
  }
}
js
const myGreatMixin = {
  // ...
  methods: {
    _update() {
      // ...
    }
  }
}
js
const myGreatMixin = {
  // ...
  methods: {
    $update() {
      // ...
    }
  }
}
js
const myGreatMixin = {
  // ...
  methods: {
    $_update() {
      // ...
    }
  }
}

Correcto

js
const myGreatMixin = {
  // ...
  methods: {
    $_myGreatMixin_update() {
      // ...
    }
  }
}
js
// ¡Aún mejor!
const myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin
Reglas de Prioridad A: Esencial has loaded