Category Archives: programación

programación

Soporte para TypeScript en Vuejs

Este artículo es una traducción de la documentación oficial. Mis notas estarán debidamente identificadas.

Soporte para TypeScript

A partir de la versión de Vue 2.5.0 en adelante se ha mejorado significativamente las declaraciones de tipos para que operen con el API default basado en objectos. Al mismo tiempo se ha introducido algunos cambios que requieren se realice una debida actualización. Leer el siguiente artículo para más detalles.

Nota: Con esta introducción se reafirma el compromiso del equipo de Vue para mantener un ambiente saludable y ágil a la hora de trabajar con TypeScripte dentro de Vue.

Declaración oficial en los paquetes de NPM

Un sistema de tipado estático puede ayudar a prevenir muchos potenciales errores de runtime, especialmente cuando la aplicación continúa creciendo. Es por esto que Vue ofrece soporte oficial a las declaraciones para tipado estático en TypeScript – no solo para el core de Vue, sino también para las librerías vue-router y vuex.

Dado que estas están publicadas en NPM, y la versión más reciente de TypeScript sabe como resolver las declaraciones de tipo en los paquetes de NPM, esto significa que cuando se instala a través de NPM, no se necesita ninguna herramienta adicional para habilitar TypeScript en Vue.

Nota: Actualmente TypeScript cuenta con una rica colección de tipos gracias al esfuerzo del colectivo Definitely Typed y a la aceptación en general de la comunidad.

Configuración recomendada

// tsconfig.json
{
  "compilerOptions": {
    // esto se alinea con el soporte de Vue en el navegador 
    "target": "es5",
    // permite una inferencia más estricta para las propiedades de datos en `this`
    "strict": true,
    // si se usa webpack 2+ o rollup, para aprovechar el método tree shaking:
    "module": "es2015",
    "moduleResolution": "node"
  }
}

Tenga en cuenta que debe incluir strict: true (o al menos noImpllicitThis: true, que es parte del flag strict) para aprovechar la verificación de tipo para this en los métodos de los componentes, de lo contrario, siempre se tratará como tipo any.

Consulte la documentación de TypeScript para más detalles sobre las opciones del compilador.

Herramientas para desarrollo

Creación de proyectos

Vue CLI 3 puede generar proyectos compatibles con TypeScript. Para comenzar:

# 1. Instalar Vue CLI si aún no lo ha instalado
npm install --global @vue/cli

# 2. Crear un nuevo proyecto, luego seleccione la opción "Manually select features"
vue create mi-proyecto

Soporte en el editor

Para desarrollar aplicaciones usando Vue y TypeScript, se recomienda usar Visual Studio Code, el cual cuenta con soporte nativo para TypeScript. Si usas componentes en modo sigle-file (SFCs), instala la increíble extensión Vetur, que proporciona inferencia de TypeScript dentro del SFC y ofrece una gran cantidad de excelente opciones.

WebStorm también cuenta con soporte nativo para ambos, TypeScript y Vue.

Nota: Vetur es una estupenda herramienta para Vue. Aún si no deseas utilizar TypeScript es una extensión que deberías explorar y añadir al repertorio.

Uso básico

Para que TypeScript infiera adecuadamente los tipos dentro de un componente en Vue, necesitas definir los componentes usando Vue.component o Vue.extend:

import Vue from 'vue'

const Component = Vue.extend({
  // inferencia de tipo habilitada
})

const Component = {
  // aquí NO habrá inferencia de tipos,
  // porque TypeScript no puede inferir que esto son opciones para un componente Vue.
}

Componentes Vue utilizando el modelo Class-Style

Si prefieres una API basada en clases para declarar componentes, puedes usar el decorador oficial vue-class-component:

import Vue from 'vue'
import Component from 'vue-class-component'

// El decorador @Component le indica a la clase que es un componente Vue
@Component({
  // Todas las opciones del componente se definen aquí
  template: '<button @click="onClick">Click!</button>'
})
export default class MyComponent extends Vue {
  // La data inicial puede ser declarada como propiedades de la instancia
  message: string = 'Hello!'

  // Los métodos del componente pueden ser declarado como métodos de la instancia
  onClick (): void {
    window.alert(this.message)
  }
}

Nota: Los decoradores usan una sintaxis especial a través del símbolo @ y se colocan inmediatamente antes de que se decore el código. En la programación orientada a objetos, el patrón decorador (también conocido como Wrapper, nombre alternativo al patrón Adapter) es un patrón de diseño que permite agregar comportamiento a un objeto individual, ya sea estática o dinámicamente, sin afectar el comportamiento de otros objetos de la misma clase. Al momento de redactar este artículo, JavaScript no cuenta con apoyo nativo para decoradores. Existe la propuesta para añadirlo al spec y actualmente se encuentra en el borrador, “Stage 2 Draft / May 23, 2018”.

Aumento de tipos para uso en plug-ins

Los plug-ins pueden agregarse a las propiedades globales/instancia de Vue y a las opciones de los componentes. En estos casos, se necesitan declaraciones de tipo para hacer que los plug-ins se compilen en TypeScript. Afortunadamente, hay una característica de TypeScript para aumentar los tipos existentes llamada aumento de módulos (module augmentation.).

Por ejemplo, para añadir una propiedad a la instancia llamada $myProperty de tipo cadena:

// 1. Asegurate importar 'vue' antes de la declaración aumentada para los tipos
import Vue from 'vue'

// 2. Especifique el archivo con los tipos que desea aumentar 
//    Para el constructor Vue este se encuentra en types/vue.d.ts
declare module 'vue/types/vue' {
  // 3. Utilice la propiedad aumentada en Vue
  interface Vue {
    $myProperty: string
  }
}

Luego de incluir el código anterior como un archivo de declaraciones (algo parecido a my-property.d.ts) en tu proyecto, puedes usar myProperty en la instancia de Vue.

var vm = new Vue()
console.log(vm.$myProperty) // Esto debería compilar sin problema

También puedes declarar propiedades globales adicionales y opciones en los componentes:

import Vue from 'vue'

declare module 'vue/types/vue' {
  // Propiedades Globales pueden ser definidas
  // en la interface `VueConstructor`
  interface VueConstructor {
    $myGlobal: string
  }
}

// ComponentOptions se define en types/options.d.ts
declare module 'vue/types/options' {
  interface ComponentOptions<V extends Vue> {
    myOption?: string
  }
}

Las declaraciones anteriores permiten que el siguiente código pueda ser compilado:

// Propiedad Global
console.log(Vue.$myGlobal)

// Opción adicional
var vm = new Vue({
  myOption: 'Hello'
})

Anotación de tipos para resultados

Debido a la naturaleza circular de los archivos de declaración de Vue, TypeScript puede tener dificultades para inferir los tipos de ciertos métodos. Por esta razón, es posible que deba anotar el tipo del resultado en métodos como render y computed.

import Vue, { VNode } from 'vue'

const Component = Vue.extend({
  data () {
    return {
      msg: 'Hello'
    }
  },
  methods: {
    // necesita una anotación debido al uso de `this` en el resultado
    greet (): string {
      return this.msg + ' world'
    }
  },
  computed: {
    // necesita una anotación
    greeting(): string {
      return this.greet() + '!'
    }
  },
  // `createElement` es inferido pero `render` necesita la anotación
  render (createElement): VNode {
    return createElement('div', this.greeting)
  }
})

Si encuentra que la inferencia de tipo o la resolución del método no funciona, anotar ciertos métodos puede ayudar a resolver estos problemas. Usar la opción --noImplicitAny ayudará a encontrar muchos de estos métodos no anotados.

Nota: Es importante destacar que el uso de tipos no es un requisito para todos los proyectos. Utilizar TypeScript tampoco lo es. Las ventajas son inmensas pero la curva de aprendizaje puede ser atropellada si no se evalúa correctamente al momento de introducirlo en el proyecto o al equipo de trabajo. Tómese su tiempo y no tema en experimentar con esta tecnología.

programación

Funciones Arrow

A continuación les comparto un abstracto de uno de los capítulos que estoy trabajando para un manual sobre JavaScript. Sugerencias y comentarios son bienvenidos.

Funciones Arrow

Anteriormente habíamos mencionado que a través de las funciones anónimas podiamos ahorrarnos el nombre de la función al momento de la declaración. ¿Qué tal si también pudiéramos ahorrarnos utilizar las palabras function y return? ¿Pudiéramos crear algo como esto?:

let myFunction = (){}

Bueno, dicha expresión produce el siguiente error: Uncaught SyntaxError: Unexpected token. El mensaje de error nos proveer una breve idea de lo que necesitamos para que podamos declarar la función. Dicho token o identificador es el famoso fat arrow o función flecha: =>. Para propósitos de claridad le llamaremos función arrow.

let myFunction = () => {}

Las ventajas primordiales de las funciones arrow son las siguientes:

  • Usan menos keywords. Ejemplo:
const myArray = [1, 2, 3];
const squares = myArray.map(x => x * x);
// No necesita utilizar el keyword function ni return

Veamos que significa todo esto a través de ejemplos. De todas esas variables especiales nos concentraremos en this.

Si fuéramos a utilizar todos los keyword que nos ahorramos con el uso de funciones arrow tendríamos algo así.

const myArray = [1, 2, 3];
const squares = myArray.map(function (x) {
  return x * x
});

Veamos como luce finalmente. Lo primero que vamos hacer es remover las palabras innecesarias, function y return.

const squares = myArray.map((x) => {x * x});

Hay ciertas reglas que podemos seguir a la hora de construir funciones arrow. Si solamente tenemos un parámetro, x en este caso, no necesitamos de paréntesis.

const squares = myArray.map(x => {x * x});

Además, en este ejemplo estamos devolviendo una expresión. Por lo tanto otra regla que podemos aplicar es, si la función devuelve solo una expresión, no necesitamos las llaves o corchetes.

const myArray = [1, 2, 3];
const squares = myArray.map(x => x * x);
// resultado de squares es [1, 4, 9]

Hermoso ¿no? Ahora veamos como se afecta el binding usando funciones arrow. Primero repasemos que eso del binding y su importancia.

¿Qué es this?

En JavaScript existe la palabra reservada this, que a su vez es un objeto, y está estrictamente relacionado al uso de funciones. Si deseamos saber que es this solo es necesario ejecutar un console.log(this) para explorar su contenido. El resultado de esto es el objecto window el cual representa el contenido del documento DOM y otras cosas más (funciones, métodos, etc), y solo está disponible en el navegador; es básicamente la raíz por donde se propagan todas las propiedades y objetos. Veamos un ejemplo.

Nota: En node.js no existe el objeto window.

console.log(this === window) // True

El ejemplo anterior claramente muestra que ambas cosas son lo mismo. Si creamos la siguiente variable:

var myName = 'Jaime'

Hacer un console.log de window.myName debe imprimir ‘Jaime’. Te recomiendo hagas el experimento.

Nota: No es un despiste que haya declarado la variable usando var en vez de let o const. El asunto aquí es que las variables declaradas var van directamente al objeto global window pero en cambio let y const están restringidas a un entorno declarativo que no puedes acceder a través del objeto window.

Sigamos con this y las funciones arrow para entender como se afectar el binding. Ya que el valor de this puede cambiar según una función es invocada, o sea, dependiendo del contexto en el cual se llama la función, es posible que confundamos el contenido del objeto. Cuando quizás deseabas acceder ciertas propiedades te das cuenta que estas obteniendo el resultado de otro objeto que muy probablemente no tiene lo que estas buscando o esperando. Recuerda, this es un objecto que va a depender de quien, donde y como se invoque la función. Y esto es importante tenerlo claro para entender como se comporta en las funciones arrow (y en generar cuando programas en JavaScript). Hagamos un ejemplo Franquestein usando la función arrow para calcular cuadrados pero dentro de un objeto (patrón muy común).

A continuación tenemos un objecto que contiene la funcionalidad de crear números al cuadrado. Digamos que se añade un nuevo requisito para sumar 1 a cada cuadrado.

const squares = {
  arr: [1, 2, 3],
  num: function () {
    return this.arr.map(function (x) {
      return (x * x) + this.add()
    })
  },
  add: function () {
    return 1
  }
}

console.log(squares.num())

El código anterior reportara un error indicando que this.add no es una función. Realmente no existe en el contexto de la función o funciones definidas en num, no hay un puente que me pueda llevar de num a add ya que this esta apuntando al objecto window y la función add existe solo en el contexto del objeto squares. Es importante entender esto. Para resolver el problema sin usar funciones arrow solo necesitamos traernos o redirigir this y pegarlo donde lo necesitemos. Eso lo hacemos a través del método bind.

const squares = {
  arr: [1, 2, 3],
  num: function () {
    return this.arr.map(function (x) {
      return (x * x) + this.add()
    }.bind(this))
  },
  add: function () {
    return 1
  }
}

Ahora efectivamente podemos usar la función add dentro de num. Hemos creado el puente utilizando bind. Con el uso de funciones arrows no tenemos que preocuparnos por este binding ya que al usar funciones arrow estas no manejan el binding como tradicionalmente se hace usando function. Como estamos tan entusiasmados con las funciones arrow, vamos a cambiar toda la función num a funciones arrow.

num: () => {
    return this.arr.map((x) => {
      return (x * x) + this.add()
    })
  }

¡HEY, STOP! No todo es color violeta. La documentación oficial indica que las funciones arrow son más adecuadas para funciones no relacionadas a métodos.

const squares = {
  arr: [1, 2, 3],
  num: () => {
    // Error, uso no aduacuado para funciones arrow
    return this.arr.map((x) => {
      return (x * x) + this.add()
    })
  },
  add: () => {
    return 1
  }
}

Finalmente nuestro ejemplo quedaría así:

const squares = {
  arr: [1, 2, 3],
  num: function () {
    return this.arr.map(x => (x * x) + this.add())
  },
  add: () => {
    return 1
  }
}

Si te revienta la cabeza, relax, toma tiempo digerir todo esto. Lo más importante es recordar que el objeto this dependerá de donde, quien y como invoca x o y función y que las funciones arrow utilizan el contexto de this que le ofrece el marco en donde son ejecutadas. Esto nos lleva al próximo tena que tiene que ver mucho con el lexical scoping en JavaScript.

¡Hasta la próxima!

programación

Recordatorio a validar tu código

Respecto a escribir pruebas para tu código (TDD y otros) y validarlo (Integration Testing):

“Entonces, por supuesto, hazlo de otra manera si eso es lo que mantiene tu bote a flote. Pero sé honesto contigo mismo sobre tus razones [de no tener pruebas de validación]. Eventualmente, sea cual sea tu justificación, tu código revelará la historia real.”

Tomado del cierre del artículo Don’t Want to TDD? Don’t TDD. Just Be Honest About Your Reasons.

programación

Mejor manejo de paquetes en npm

npm es de esas herramientas que una vez usas te das cuenta que has creado una dependencia inmediata. Si eres un JavaScript developer el valor que provee es impresionante. Así mismo podemos perder el hilo de los paquetes que hayamos instalado o estén “fuera de moda”. Hay tres instrucciones que nos pueden proveer luz y control al proceso de manejo de paquetes.

  • list
  • outdated
  • prune

Consejo, nunca actualizes ciegamente las dependencias en tu proyecto. Para saber cuales son los paquetes que hemos instalado de forma global usamos npm list -g --depth=0. Si solo deseamos ver los paquetes de nuestro proyecto omitimos g.

Si deseas discriminar entre los paquetes en producción y development usas --prod y --dev respectivamente.

Ahora viene lo interesante. Para poder visualizar el estatus de las versiones de los paquetes, utilizas npm outdated. Esta opción generará un hermoso listado que indica el nombre de la dependencia, que versión está instalada, cual es la versión que se desea según la configuración de la versión semántica y cuál es la versión más reciente disponible.

Y por último npm prune para limpiar la carpeta de paquetes node_modules. Si le añades --production los paquetes que estén marcados como paquetes de desarrollo serán removidos.

¿Tienes algún consejo para el manejo de paquetes en npm? Déjamelo saber en la sección de comentarios.

programación

Los sabores de Vue.js – Standalone y Runtime-only

Anteriormente hemos hablado como instalar Vue.js para crear nuestras aplicaciones web. A continuación, me gustaría tocar el tema de como funcionan los dos sabores disponibles para crear nuestros componentes y por ende nuestra aplicación. En la documentación de Vue.js estos dos sabores son llamados Full distribution y Runtime-only distribution. Por conveniencia vamos a llamar de ahora en adelante a la versión Full, Standalone. Veamos que las hace especial y cómo podemos sacar mejor provecho a la hora de comenzar nuestro proyecto.

Standalone

Esta es la versión que comúnmente utilizamos cuando empezamos con Vue.js. Aquí encontraremos el compilador y el runtime para ejecutar toda la magia de Vue.js. El compilador es el encargado de transformar todo lo que tenemos en nuestro template a funciones render de JavaScript. Este señor se encarga de hacer “todo el trabajo pesado” por nosotros. Cuando utilizas Vue.js desde tu navegador a través de la etiqueta <script>, básicamente estas cargando el compilador y el runtime.

Aquí lo más importante es recordar que el compilador es el encargado de compilar el html o los templates para hacer el rendering al navegador.

Runtime-only

Esta versión no incluye la opción o la habilidad de compilar in-DOM templates como lo hace la versión Standalone. Para poder mostrar html en el navegador debes hacerlo a través de una función de render. A fin de cuentas así es como lo hace la versión Standalone. En realidad, la única tarea que no podemos realizar con el Runtime es la compilación de templates. Todo lo demás es posible – crear instancias, manejar el Virtual DOM, reactividad, ya sabes, todo menos compilar templates.

Hacer render más allá del navegador

Cuando usas la versión Standalone, esta usa los API disponibles a través del navegador para hacer el rendering. La versión Runtime-only no posee esta habilidad. Pero esta carencia le brinda la flexibilidad de poder hacer rendering en ambientes donde no existe la presencia de un navegador, por el ejemplo, en el servidor. No vayas a pensar que la versión Runtime-only es inferior, por el contrario, esto le permite a Vue.js poder ejecutarse en lugares antes no posible. Proyectos como Weex (similar a React Native) y Nuxt.js (Server-Side Rendering usando Vue.js) son posibles gracias al Runtime. Técnicamente el Runtime es el corazón de Vue.js.

Componentes en un archivo único

Continuando con el tema de fortalezas y desventajas, para proyectos pequeños o prototipos rápidos no hay mejor opción que usar la versión Standalone. Ya cuando el proyecto haya crecido suficiente o entiendas que es de una complejidad moderada lo mejor es usar directamente el Runtime. Ahora bien y como ya hemos mencionado, la única mejor manera de usar el Runtime es a través del Vue-cli y usar Single File Components. El problema con los templates es que terminas escribiendo CSS o HTML dentro de un archivo JavaScript, a lo JSX, para arreglar las cosas del HTML en el JavaScript. Aquí es donde Vue.js se destaca de los demás. Los componentes de un solo archivo de Vue es probablemente una gran solución, que te permite poner todo lo relacionado a un componente en un solo lugar resolviendo un gran número de decisiones en torno a la arquitectura de componentes.

Un asunto a considerar es si deseas moverte de usar la versión Standalone a usar solo el Runtime. Ir del código en versión Runtime-only a Standalone es un paseo, técnicamente le has hecho un favor al compilador. Ahora bien, para ir viceversa, de Standalone a Runtime-only tendrás que rescribir todos los componentes para usar funciones render.

Ejemplos

El artículo 7 Ways To Define A Component Template in Vue.js contiene excelentes ejemplos de como crear componentes en Vue.js. No los copiaré aquí pero en resumen los ejemplos de 1-4 usan la versión Standalone y los ejemplos 5-7 usan solo el Runtime.

De no tener claro las ventajas y desventajas de ambos sabores, no dudes en comentarlo.

programación

React Snippets código fácil sin compromiso

Repetir lo mismo una y otra vez es una tarea tediosa. A la hora de crear clases en React te das cuenta que la misma base se repite una y otra vez a lo largo de los componentes. Una forma de atacar esta incomodidad es a través del uso de snippets. Los snippets son bloques de texto predefinidos que podemos añadir a nuestro código con el uso de atajos. Es el mismo concepto de los Emmet. Veamos como configuramos los snippets en Visual Studio Code.

Lo primero es buscar el lenguaje que vamos a impactar. File > Preferences > Users Snippets. En nuestro caso vamos a buscar por JavaScript React ya que lo que queremos es mejorar la experiencia al momento de escribir código de JSX.
search snippets react

Al escoger el lenguaje VSCode te mostrara un archivo tipo json con un ejemplo de cómo crear tus propios snippets. En nuestro caso vamos a utilizar el formato ya definido en el siguiente repositorio en Github. Solo necesitamos copiar el contenido del archivo snippets.json. Yo acostumbro cerrar y abrir el editor para saber que VSCode capturó el cambio.

¡Listo! Ahora cada vez que vayas a trabajar un documento JSX tendrás la opción de añadir varios bloques de código con tan solo presionar algunas teclas.

El listados completo de los atajos lo puedes revisar en el Read Me del repositorio. Si deseas realizar todo esto a través de una extensión, no hay problema, también existe.

programación

¿Qué es Redux?

Redux es una librería que se encarga de emitir actualizaciones de estado en respuesta a acciones. En lugar de modificar directamente el estado, la modificación se maneja a través de objetos sencillos llamados acciones. Luego escribes una función especial llamada reductor para decidir cómo cada acción transforma el estado de toda la aplicación. Y por último todo se maneja desde un solo lugar llamado store (ya somos experto en Redux! No?). Ya que la repetición nos ayuda a recordar las cosas podemos decir que los elementos principales de esta arquitectura o patron de diseño son:

  • Acciones
  • Reducers
  • Store

La librería Redux en sí es sólo un conjunto de ayudas para “montar” reductores a un único objeto de store global. Veamos los detalles.

Redux overview
Ilustración por Lynn Fisher

Aunque no sea importante para entender qué es Redux, debemos indicar que para instalar la versión estable usamos npm:

npm install --save redux

Principios fundamentales

Como los requisitos para las aplicaciones tipo SPA en JavaScript se han complicado cada vez más, nuestro código debe gestionar más states que nunca. Las librerías como React, Angular y Vuejs intentan resolver parte de este problema en el layer de vista eliminando tanto la asincronía como la manipulación DOM directa. Sin embargo, la gestión del state de la data se deja a tu discreción. Aquí es donde Redux entra.

Redux intenta hacer predecible las mutaciones de estado imponiendo ciertas restricciones sobre cómo y cuándo pueden suceder las actualizaciones. Estas restricciones se reflejan en los tres principios de Redux.

Única fuente de verdad

El estado de toda la aplicación se almacena en una estructura de árbol dentro de un único store.

Esto hace que sea fácil crear aplicaciones universales, ya que el estado en el servidor puede ser serializado e hidratado en el cliente sin ningún esfuerzo adicional de codificación. Un solo árbol de estado también facilita la depuración o la introspección de una aplicación. Esto permite que el ciclo de desarrollo sea más rápido.

El estado es read-only

La única manera de cambiar el estado es emitir una acción, un objeto que describe lo sucedido.

Esto garantiza que nada modificará directamente al estado de tu aplicación. Por el contrario, la acción expresa una intención de transformar el estado. Debido a que todos los cambios están centralizados y suceden uno por uno en un orden estricto, no hay race conditions que necesitemos monitorear. Dado que las acciones son objetos sencillos, se pueden registrar, serializar, almacenar y reproducir posteriormente para fines de depuración o pruebas.

Los cambios se realizan a través de funciones puras

Para especificar cómo se transforma el estado por acciones, se escriben reducers puros.

Los reducers son funciones puras que toman el estado anterior y una acción, y devuelven el siguiente estado. Esta función debe devolver objetos que presentan el nuevo estado, en lugar de cambiar el estado anterior. Puedes comenzar con un solo reductor y, a medida que la aplicación vaya creciendo, divídelo en reductores más pequeños que administren partes específicas del estado.

Actions

Las acciones son cargas útiles de información que envían datos desde su aplicación a su store. Son la única fuente de información para el store. Los envía al store mediante el método store.dispatch ().

Las acciones son simples objetos en JavaScript. Las acciones deben tener una propiedad conocida como type que indica el tipo de acción que se está realizando. Los types normalmente se deben definir como una cadena de constantes. Una vez la aplicación haya crecido, puedes mover las acciones a módulos independientes. Veamos un ejemplo:

var action = {
  type: 'ADD_USER',
  user: {name: 'Dan'}
};

Action Creators

Los creadores de acciones son exactamente eso, funciones que crean acciones. Es fácil combinar los términos “acción” y “creador de acción” al momento de buscarle nombres a nuestros elementos, así que haz lo mejor que puedas para usar el término apropiado. Así evitaras confusiones.

// Action type
const ADD_USER = 'ADD_USER';

// Action Creator
var addUser = function(name) {
  return { type: ADD_USER, name}
}

// Dispatch envía un object
store.dispatch(addUser('Jaime'));

La función dispatch() se puede accesar directamente desde el store como store.dispatch(), pero es más conveniente utilizar el método connect() que tenemos en la librearía react-redux. Puedes utilizar bindActionCreators() para asociar automáticamente cuantos creadores de acción desees a la función dispatch(). Ya empezamos a tocar un poco de profundidad asi que mejor vamos a continuar con el próximo tema.

Reducers

Las acciones describen el hecho de que algo ocurrió, pero no especifican cómo cambia el estado de la aplicación en respuesta a esa intención de cambio. Este es el trabajo de los reductores. El reductor es una función pura que toma el estado anterior y una acción, y devuelve el siguiente estado.

(previousState, action) => newState

Es muy importante que el reductor se mantenga puro. Cosas que nunca debes hacer dentro de un reductor:

  • Modificar sus argumentos (entonces ya no es una función pura)
  • Ejecutar acciones como llamadas a algún API o jugar con las rutas (routes)
  • Ejecutar funciones no-puras, por ejemplo Date.now(), Math.random(), etc

La documentación es enfática en destacar que el reductor debe ser puro. Dado los mismos argumentos, debes calcular el siguiente estado y devolverlo. Sin sorpresas. Sin efectos secundarios. No llamadas de API. No mutaciones. Sólo una simple evaluación. Veamos un ejemplo:

import { combineReducers } from 'redux'
import { ADD_USER } from './actions'

function users(state = [], action) {
  switch (action.type) {
    case ADD_USER:
      return [
        ...state,
        {
          text: action.text
        }
      ]
    default:
      return state
  }
}

const reducers = combineReducers({
  users
})

export default reducers

Store

Como hemos visto las acciones representan los hechos sobre “lo que pasó” y los reductores actualizan el estado de acuerdo a esas acciones. El store es el objeto que los reúne (yey!). El objeto store tiene las siguientes responsabilidades:

  • Almacena el estado de aplicación
  • Permite el acceso al estado a través del método getState()
  • Permite que el estado se actualice a través del método dispatch(action)
  • Registra los listeners mediante el método subscribe(listener)
  • Maneja remover el registro de los listeners a través de la función que invocó al subscribe(listener). Te lo aclaro con el siguiente ejemplo:
const remove = subscribe(myListener);
// para remover:
remove();

Ya cubierto lo básico podemos tener una idea de lo que es Redux. Veamos el ejemplo completo (en producción se debe perseguir crear módulos para cada parte):

// Reducers
const users = (state = [], action) => {
  switch (action.type) {
    case 'ADD_USER':
      return [
        ...state, {
          text: action.text
        }
      ]
    default:
      return state
  }
}

//Actions
const addUser = (text) => {
  return {
    type: 'ADD_USER',
    text
  }
}

// Redux y amigos
const { combineReducers, createStore } = Redux
const userApp = combineReducers({ users })

let store = createStore(userApp)
// Registra el estado inicial
console.log(store.getState())

// cada vez que haya un cambio en el state, registrarlo
// Observa que la función subscribe() devuelve una función para remover el listener
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

// Dispatch some actions
store.dispatch(addUser('Wolverine'))
store.dispatch(addUser('Batman'))
store.dispatch(addUser('Ironman'))

// Remover listeners a la actualización del state
unsubscribe()

Conclusión

Esto es solo el comienzo. Esta arquitectura puede parecer un poco pesada para proyectos pequeños, pero la belleza de este patrón de diseño es lo bien que escala en aplicaciones grandes y complejas. Además, es fácil de integrar en ya sea en React, Angular, Vuejs etc.

programación

Componentes Vue.js en español

Vayamos rápido al grano sobre el tema de componentes en Vue.js. Por ahora, sólo necesitas saber que todos los componentes en Vue son esencialmente una extensión a la instancia de Vue.

// Instancia Vue
new Vue({
  el: '#some-element',
  // options
})

Utilizando el entorno ofrecido por la herramienta vue-cli, vamos a utilizar los archivos iniciales para ver como trabajamos con los components. Veamos el siguiente ejemplo:

import Vue from 'vue'
import App from './App.vue'

// Extendemos las instancia para crear los componentes
Vue.component('comp1', {
  template:'<div>Component 1</div>' 
}) 

Vue.component('comp2', { 
  template:'<div>Component 2</div>' 
}) 

Vue.component('comp3', { 
  template:'<div>Component 3</div>' 
}) 

// Instancia de Vue 
new Vue({ 
  el: '#app', 
  render: h => h(App) 
})

Continuar la lectura…

programación

Construir un ambiente de desarrollo para Vue.js usando Webpack

Después de haber escrito sobre lo básico de Vue.js es momento de pasar al próximo nivel, Vue.js usando Webpack. La idea este “próximo nivel” es poder tener un ambiente relativamente completo para desarrollar nuestro front-end.

Vue ha desarrollado una herramienta increíblemente práctica para este propósito. La herramienta es conocida como vue-cli y contiene todo lo necesario para arrancar el ambiente de desarrollo. Lo bueno de utilizar esta herramienta es que provee una manera oficial y opinionada de empezar un proyecto. Además provee espacio para adaptarlo a nuestra necesidades y gustos.

Para comenzar a utilizar vue-cli debes tener: Node.js (>=4.x, 6.x siendo preferido) y Git. En cuanto a npm una recomendación es tener npm >= 3.x.

Instalamos de la siguiente manera:

$ npm install -g vue-cli

Actualmente los templates oficiales disponible son:

  • webpack
  • webpack-simple
  • browserify
  • browserify-simple
  • simple

Si deseas utilizar vue-cli para trabajar con tu propio template los puedes hacer fácilmente. La documentación oficial lo explica con lujo de detalle.

Para propósitos de este tutorial y porque es el template que más utilizo estaremos trabajando con webpack. Esta versión es bien completa e incluye todo lo que necesitamos: Webpack Dev Server, Babel setup, Hot Reloading, Unit Testing, etc.

Ya que hemos instalado vue-cli, vamos a utilizarlo para crear nuestro proyecto y de una vez procederemos a instalar las dependencias.

$ vue init webpack my-project

$ cd my-project

$ npm install

Ya con todo en su lugar vamos a inicial el proyecto.

$ npm run dev

Conclusión

Es hora de repasar que tenemos hasta el momento. Hemos creado un proyecto a través de la herramienta vue-cli. Esta herramienta utiliza Webpack para manejar todo el ambiente de desarrollo de Vue. Nada “fancy” por el momento pero si analizamos todo lo que tenemos con tan solo usar vue-cli, comprenderemos el gran ahorro en tiempo y stress que esta simple herramienta nos provee.

programación

Malas costumbres

Recientemente estuve escuchando el episodio Two Anti-Patterns To Avoid del podcast Developer Tea (excelente podcast por cierto). En el episodio Jonathan Cutrell discute dos anti-patrones, o como mejor me gusta llamar, malas costumbres que podemos cometer en el código fuente de nuestro proyecto. Inicialmente pensé en saltarme el episodio pero teniendo en cuenta que solo discutiría dos me dio curiosidad. De todas esas cosas que sabemos no debemos hacer pero aún así hacemos mientras programados me llamó la atención que dos cosas el anfitrión destacaría en la conversación. Continuar la lectura…