martes, 26 de septiembre de 2017

Diseño Anticipatorio: Cómo Crear Experiencias de Usuarios Mágicos


Esta mañana la canción “This Magic Moment” de The Drifters apareció en mi cabeza sin ninguna razón aparente.
Esas inquietantes redes neuronales en nuestro cerebro hacen cosas divertidas. Hacen que aparentemente conceptos y pensamientos no relacionados se conectan.
Golpeándome la frente me dije: “Pero, por supuesto …”
Recientemente he estado pensando en esos momentos mágicos en UX que suceden cuando interactuamos con nuestros dispositivos o servicios digitales. Encontramos momentos perfectos, cuando todo cae en su lugar, exactamente en el camino correcto, exactamente en el momento adecuado, como si fuera mágico. Podría ser en tu banco, en tu coche, una máquina expendedora, o en tu teléfono.
Creo que la era del diseño anticipatorio está aquí, o al menos a nuestro alcance.
Nuestras GUIs limitadas están cambiando como resultado de la evolución de las tecnologías y los métodos de entrada. Es una evolución orgánica, natural - ¡ por supuesto, ya estamos hablando con nuestros dispositivos!
Por ejemplo, mientras conducimos podríamos decir: “Llama a Anna.” Le pedimos a Siri que inicie un cronómetro o que las películas estén jugando cerca. Y le pedimos a Alexa que toque música o nos ordene el café. Sin embargo, las metáforas y los elementos gráficos establecidos hace más de cuatro décadas no han cambiado mucho.

El Pasado

Ten en cuenta que la GUI original de Xerox PARC tiene 44 años, pero nuestras interfaces de usuario todavía se ven muy bien.
La estación de trabajo Xerox Star introdujo el primer sistema operativo de interfaz gráfica de usuario (GUI) comercial en 1973
Hoy en día, todavía estamos viendo pantallas bidimensionales y en su mayoría utilizan teclados y ratones para la entrada, dispositivos diseñados para métodos de interacción optimizados para ordenadores, no para humanos.
Las máquinas con las que interactuamos - ordenadores portátiles, escritorios, tablets,móviles , máquinas expendedoras, etc., diseñados y construidos con modelos mentales y tecnologías que son sistemas heredados del pasado.
Es como si estuviéramos utilizando modelos de interacción de la era de Los Picapiedras en un mundo de Los Supersónicos. Todavía dependen de mucha interacción de los usuarios (entrada) para pasar al siguiente paso y mostrar información útil (salida).

¿Qué es el diseño anticipatorio?

La aplicación del diseño anticipatorio es más importante que nunca si las empresas digitales son para simplificar y facilitar el curso de nuestras vidas digitales.
A la luz de esto, ¿qué es el diseño anticipatorio?
Es de salida, sin mucha necesidad de entrada.
Un mundo donde nuestras máquinas de computación están diseñadas para los métodos de interacción optimizados para los seres humanos, no para las computadoras. Un mundo digital donde nos movemos de la intención del usuario que es determinista a probabilística.
Aaron Shapiro de Hugedefine el diseño anticipatorio como un método para simplificar los procesos respondiendo a las necesidades un paso por delante de las decisiones del usuario, es decir, respondiendo a las necesidades de los usuarios que aún no han expresado.
El diseño anticipado en su forma más fina va mucho más allá de la personalización.
Por ejemplo, Netflix que muestra películas para ver en función de tus preferencias y el historial para la personalización. Con un diseño anticipado, la interfaz cambia realmente en el momento en que estás interactuando con una aplicación.
An example of personalization-not anticipatory design.
El diseño anticipatorio significaría -en el caso de las compras en línea, por ejemplo- que el sistema conocería y personalizaría una experiencia en la medida en que se sentiría como una mano mágica guiando tu experiencia. En realidad, cambiaría la interfaz de usuario al instante, eliminaría cualquier información extraña y sólo presentaría las opciones más relevantes de manera oportuna, sencilla y eficiente.
Esto no es demasiado difícil de lograr hoy.
Digamos que alguien está comprando una guitarra muy cara en guitarcenter.com. Al momento de pagar el sitio presentaría automágicamente “enviar a la tienda para ser recoger” como una opción por defecto porque sabe al observar el comportamiento pasado de otros usuarios comprando guitarras caras, estos preferirían recogerlas en la tienda más cercana.
Para otro ejemplo, vamos a fingir que estás comprando una camisa en Amazon.
Amazon ya personaliza toda una serie de cosas para ti y debe saber tu tamaño y las preferencias de color ya que has comprado camisas en el sitio antes.
Al ir a la página de detalles del producto, podría pre-seleccionar tu tamaño, y mostrar las de color azul marino, blancas y a cuadros en primer lugar, y no poner importancia en los rosados ​​y amarillos, y no obligarte a seleccionar tu tamaño cada vez que veas distintas camisas.

¿Por qué?

La promesa del diseño anticipatorio es la eliminación de la fricción y un aumento en la eficiencia que mejoraría en gran medida las experiencias de los usuarios y, a su vez, impactaría en los resultados. La gente vuelve a los productos y servicios que ofrecen lo que quieren cuando lo desean.
Nuestras interacciones diarias con sistemas digitales han alcanzado una escala sin precedentes. Sin embargo, muchas de estas interacciones se sofocan con fricción y sentimientos subsiguientes de frustración.
Hay una necesidad real de personalización y en una escala mayor que deleitaría a los usuarios, y simplificar sus vidas.
Toma las máquinas expendedoras de billetes de autoservicio (ó ATMs), donde los viajeros pueden recargar tarjetas de viajero.
Todavía están diseñados para ser mudos - impulsados por la entrada del usuario en el que todo el mundo se toma a través de la misma plétora frustrante de opciones.
Uno podría fácilmente imaginar un sistema mucho mejorado, más personalizado, donde el historial de recarga podría ser almacenado en su tarjeta.
En lugar de un sinnúmero de solicitudes de entrada: selecciona esta opción primero, luego selecciona esta otra opción, y así sucesivamente, toda la interacción podría comenzar con la inserción de la tarjeta que siempre se quiere recargar y el sistema inmediatamente mostraría: “Hola, ¿te gustaría volver a llenar esta tarjeta con $ 20, usando tu Mastercard? “
El siguiente paso sería pagar y terminar la operación.
Se reduciría el tiempo necesario para recargar las tarjetas por lo menos en un 75 por ciento, aumentar la eficiencia, mover a la gente más rápido y, posteriormente, hacerlos más satisfechos.
Esto ya es posible, pero no sé de una sola máquina de venta de billetes que haga esto.
Una interfaz de usuario "tonto" que requiere una gran cantidad de entrada frente a uno que es "anticipatorio"?

Interfaces del futuro.

Cuando la IA se vuelve más penetrante, un mayor grado de personalización permitirá un mayor nivel de diseño anticipatorio.
Basado en todo tipo de seguimiento de comportamiento autorizado por el usuario - historiales de compra, preferencias, etc., el sistema lo reconocería y, con un alto grado de certeza, predecirá cuál podría ser tu próxima elección.
La falta de diseño anticipatorio es sorprendente dado que las tecnologías existen hoy en día que haría que hacerlo no es tan difícil.
Algunas empresas ya están practicando las primeras formas de diseño anticipatorio. Dos ejemplos son Google Now y Uber.
Like what you're reading?
Get the latest updates first.
No spam. Just great design posts.

Google Now

La aplicación Google Now es una de las evoluciones más ambiciosas del software de búsqueda de Google.
La idea es simple: predecir lo que desearás o necesitarás saber antes de saber que lo necesitas o deseas, y servirlo en un formato de tarjeta fácil de leer.
Las capacidades de minería de datos de Google son insuperables. Sabe quién eres, y puede mostrar tarjetas con información personalizada, información de localización, como eventos de calendario, clima local, noticias, precios de las acciones, vuelos, pases de embarque, hoteles, fotos cerca y mucho más. También le dice cuánto tiempo le llevará a llegar a casa del trabajo, basado en las condiciones actuales del tráfico.
Si Google no cree que necesites algo en este momento, no se mostrará. Es la encarnación del diseño anticipatorio.

Uber

En la aplicación Uber, cuando tomas un viaje en algún lugar, proporcionará un botón de retorno en un lanzamiento posterior de la aplicación porque hay un 90 por ciento de posibilidades de que quieras volver a tu destino original. No es necesario especificar los lugares de recogida y entrega. Y eso es brillante.
La aplicación Uber ofrece a los usuarios un atajo rápido para "Volver" cuando se inicia poco después de completar un viaje

The times they are a-changin'.

Las cosas evolucionan a métodos naturales de interacción.
En un futuro no muy lejano, nuestra entrada será más fácil.
Vamos a tener realidad aumentada y virtual con métodos de interacción, como la voz, el seguimiento de los gestos, el seguimiento de los ojos y el habla. Google ya está trabajando en ello. Se llama Proyecto Soli.
Los métodos de diseño anticipados, asistidos por la IA y el aprendizaje automático, ofrecerán experiencias en un nivel completamente mejor.

¿Cómo ponemos en juego el diseño anticipatorio?

No hay varita mágica para pronunciar “abracadabra”, así que ¿cómo diseñamos para esos momentos mágicos ahora? ¿Cuáles son los pasos que podemos tomar hoy para entregar esos momentos mágicos, usando el diseño anticipatorio?
Algoritmos sofisticados y personalizados en el trabajo en Metromile crean una sensación de anticipación e increíblemente útil para los clientes (evitar entradas de estacionamiento)
Hasta que tengamos algoritmos predictivos increíblemente sofisticados, IA completamente desarrollada y aprendizaje de máquinas, las empresas pueden extraer datos existentes para oportunidades de personalización, reduciendo así los posibles puntos de dolor y barreras.
También pueden participar plenamente en el proceso de diseño centrado en el usuario, emplear investigaciones profundas, extensas pruebas de usuario y herramientas de uso, como una biblioteca de software de código abierto, para la inteligencia de la máquina, comoTensorflow.
Las investigaciones profundas nos ofrecerán una observación mucho-contextual quizás o estudios etnográficos- donde podamos observar lo que los usuarios están dispuestos a hacer de momento a momento en su flujo. Podríamos mapear estos viajes de usuario paso a paso, y diseñar la interacción en consecuencia.
El resultado ideal de la aplicación de la minería de datos y la personalización, junto con los métodos de diseño centrados en el usuario, crearía experiencias fluidas y sin precedentes anticipación que agradaría a los clientes y generar lealtad por tener las cosas aparecen como por arte de magia.
Se avanzaría el estado del arte de la experiencia del usuario y crear una situación de ganar-ganar tanto para empresas y usuarios, ofreciendo una mayor satisfacción del cliente que repercute positivamente en la línea de fondo.


El articulo original lo puede ver en el siguiente enlace..

martes, 19 de septiembre de 2017

Angular vs. React: ¿Cuál es Mejor Para el Desarrollo Web?

Angular vs. React: ¿Cuál es Mejor Para el Desarrollo Web?

Hay innumerables artículos por ahí debatiendo si React o Angular es la mejor opción para el desarrollo web. ¿Necesitamos otro?
La razón por la que escribí este artículo es porque ninguno de los artículos ya publicados –aunque contienen grandes ideas– van en profundidad para un práctico desarrollador de front-end para decidir cuál puede satisfacer sus necesidades.
Angular vs. Reaccionar: ¿Eliges la forma de framework, o juguetear con las librerías?
En este artículo, aprenderás cómo Angular y React apuntan a resolver problemas front-end similares aunque con filosofías muy diferentes, y si elegir uno o el otro es simplemente una cuestión de preferencia personal. Para compararlos, vamos a construir la misma aplicación dos veces, una vez con Angular y luego otra vez con React.

Anuncio Intempestivo de Angular

Hace dos años, escribí un artículo sobre React Ecosystem. Entre otros puntos, el artículo argumentaba que Angular había sido víctima de la “muerte por el anuncio previo”. En aquel entonces, la elección entre Angular y casi cualquier otra cosa era fácil para cualquiera que no quisiera que su proyecto funcionara con un marco obsoleto. Angular 1 era obsoleto, y Angular 2 ni siquiera estaba disponible en versión alfa.
En retrospectiva, los temores eran más o menos justificados. Angular 2 cambió dramáticamente e incluso pasó por una reescritura importante justo antes del lanzamiento final.
Dos años más tarde, tenemos Angular 4 con una promesa de estabilidad relativa de aquí en adelante.
¿Y ahora qué?

Angular vs. Reaccionar: Comparando Manzanas y Naranjas

Algunas personas dicen que comparar React y Angular es como comparar las manzanas con las naranjas. Mientras que uno es una biblioteca que se ocupa de opiniones, el otro es un framework completo.
Por supuesto, la mayoría de los Desarrolladores React añadirán algunas librerías a React para convertirlo en un framework completo. Por otra parte, el flujo de trabajo resultante de esta pila a menudo sigue siendo muy diferente de Angular, por lo que la comparabilidad sigue siendo limitada.
La mayor diferencia radica en la administración estatal. Angular viene con el enlace de datos incluido, mientras que React hoy en día suele ser aumentado por Redux para proporcionar flujo de datos unidireccional y trabajar con datos inmutables. Esos son enfoques opuestos en su propio derecho, y las discusiones incontables ahora están encendiendo si la unión mutable/de datos es mejor o peor que inmutable/unidireccional.

Un Campo de Juego Nivelado

Como React es famoso más fácil de hackear, he decidido, con el propósito de esta comparación, construir una configuración de React que refleja Angular razonablemente cerca para permitir la comparación de lado a lado de fragmentos de código.
Algunas características angulares que se destacan pero no se encuentran en Reaccionar por defecto son:
FeatureAngular packageReact library
Data binding, dependency injection (DI)@angular/coreMobX
Computed propertiesrxjsMobX
Component-based routing@angular/routerReact Router v4
Material design components@angular/materialReact Toolbox
CSS scoped to components@angular/coreCSS modules
Form validations@angular/formsFormState
Project generator@angular/cliReact Scripts TS

Enlace de Datos

La vinculación de datos es discutiblemente más fácil de comenzar que el enfoque unidireccional. Por supuesto, sería posible ir en dirección completamente opuesta, y usar Redux o mobx-state-tree con React, y ngrx con Angular. Pero eso sería un tema para otro post.

Propiedades Calculadas

Mientras que el funcionamiento se refiere, los adquiridores llanos en Angular están simplemente fuera de la pregunta mientras que se llaman en cada procesamiento. Es posible utilizar BehaviorSubject de RsJS, que realiza el trabajo.
Con React, es posible usar @computed de MobX, que logra el mismo objetivo, con una API algo mejor.

Inyección de Dependencia

La inyección de dependencia es un poco polémica porque va en contra del actual paradigma React de programación funcional e inmutabilidad. Como resulta, algún tipo de inyección de dependencia es casi indispensable en entornos de enlace de datos, ya que ayuda con el desacoplamiento (y, por lo tanto, burla y pruebas) donde no hay una arquitectura de capa de datos independiente.
Una ventaja más de DI (apoyado en Angular) es la capacidad de tener diferentes ciclos de vida de diferentes tiendas. La mayoría de los paradigmas actuales de React utilizan algún tipo de estado de aplicación global que mapea diferentes componentes, pero por mi experiencia, es demasiado fácil introducir errores al limpiar el estado global en el desmontaje de componentes.
Tener una tienda que se crea en el montaje de componentes (y estar perfectamente disponible para los hijos de este componente) parece ser realmente útil, ya menudo se pasa por alto el concepto.
Fuera de la caja en Angular, pero muy fácilmente reproducible con MobX también.

Enrutamiento

El enrutamiento basado en componentes permite a los componentes gestionar sus propias rutas secundarias en lugar de tener una configuración de enrutador global grande. Este enfoque finalmente lo ha hecho a react-router en la versión 4.

Material Design

Siempre es bueno comenzar con algunos componentes de alto nivel, y el diseño de materiales se ha convertido en algo así como una opción predeterminada universalmente aceptada, incluso en proyectos que no son de Google.
He elegido deliberadamente React Toolboxsobre el recomendado Material UI, ya que la interfaz de usuario de material tiene serias auto-confesados problemas de rendimiento con su CSS-en-línea, que planean resolver en la próxima versión.
Además, PostCSS/cssnext fue utilizado en React Toolbox y está empezando a reemplazar Sass/LESS de todos modos.

CSS con Alcance

Las clases CSS son algo así como las variables globales. Existen numerosos enfoques para la organización de CSS para evitar conflictos (incluyendo BEM), pero hay una clara corriente tendencia en el uso de bibliotecas que ayudan a procesar CSS para evitar esos conflictos sin la necesidad de un desarrollador front-end para elaborar elaborados sistemas de nombres CSS.

Validación de Formularios

Las validaciones de formulario son una característica no trivial y muy ampliamente utilizada. Es bueno tener los cubiertos por una librería para evitar la repetición de código y errores.

Generador de Proyecto

Tener un generador CLI para un proyecto es sólo un poco más conveniente que tener que clonar chapas de calderas de GitHub.

La Misma Aplicación, Construída Dos Veces

Así que vamos a crear la misma aplicación en React y Angular. Nada espectacular, solo un Shoutboard que permite a cualquiera publicar mensajes en una página común.
Puedes probar las aplicaciones aquí:
Shoutboard app en Angular vs. en React
Si deseas tener todo el código fuente, puedes obtenerlo desde GitHub:
Observará que también hemos utilizado TypeScript para la aplicación React. Las ventajas de la comprobación de tipos en TypeScript son evidentes. Y ahora, con un mejor manejo de las importaciones, async/espera y propagación de descanso finalmente llegaron a TypeScript 2, y deja a Babel/ES7/Flow en el polvo.
Además, vamos a agregar Apollo Client a ambos porque queremos usar GraphQL. Quiero decir, REST es genial, pero después de una década aproximadamente, se hace viejo.

Bootstrap y Enrutamiento

Primero, echemos un vistazo a los puntos de entrada de ambas aplicaciones.
Angular
const appRoutes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'posts', component: PostsComponent },
  { path: 'form', component: FormComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' }
]
 
@NgModule({
  declarations: [
    AppComponent,
    PostsComponent,
    HomeComponent,
    FormComponent,
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes),
    ApolloModule.forRoot(provideClient),
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    BrowserAnimationsModule,
    MdInputModule, MdSelectModule, MdButtonModule, MdCardModule, MdIconModule
  ],
  providers: [
    AppService
  ],
  bootstrap: [AppComponent]
})
@Injectable()
export class AppService {
  username = 'Mr. User'
}
Básicamente, todos los componentes que queremos utilizar en la aplicación necesitan ir a declaraciones. Todas las librerías de terceros a las importaciones y todas las tiendas globales a los proveedores. Los componentes de los hijos tienen acceso a todo esto, con la oportunidad de agregar más cosas locales.
React
const appStore = AppStore.getInstance()
const routerStore = RouterStore.getInstance()
 
const rootStores = {
  appStore,
  routerStore
}
 
ReactDOM.render(
  <Provider {...rootStores} >
    <Router history={routerStore.history} >
      <App>
        <Switch>
          <Route exact path='/home' component={Home as any} />
          <Route exact path='/posts' component={Posts as any} />
          <Route exact path='/form' component={Form as any} />
          <Redirect from='/' to='/home' />
        </Switch>
      </App>
    </Router>
  </Provider >,
  document.getElementById('root')
)
El componente  se utiliza para la inyección de dependencia en MobX. Guarda las tiendas en el contexto para que los componentes de React puedan inyectarlas posteriormente. Sí, el contexto de React puede (discutiblemente) ser utilizado con seguridad.
La versión de React es un poco más corta porque no hay declaraciones de módulo - por lo general, es sólo importar y ya está listo para usar. A veces este tipo de dependencia dura no es deseado (en pruebas), por lo que para las tiendas singleton globales, tuve que usar esteGoF patrón de vieja década:
export class AppStore {
  static instance: AppStore
  static getInstance() {
    return AppStore.instance || (AppStore.instance = new AppStore())
  }
  @observable username = 'Mr. User'
}
Angular’s Router es inyectable, por lo que puede ser utilizado desde cualquier lugar, no sólo los componentes. Para lograr lo mismo en reaccionar, usamos el paquete mobx-react-router e inyectamos el routerStore.
Resumen: Hacer bootstrapping en ambas aplicaciones es bastante sencillo. React tiene una ventaja que es más simple, usando sólo importaciones en lugar de módulos, pero, como veremos más adelante, esos módulos pueden ser muy útiles. Hacer semifallos manualmente es un poco molesto. En cuanto a la sintaxis de la declaración de enrutamiento, JSON vs JSX es sólo una cuestión de preferencia.
Like what you're reading?
Get the latest updates first.
No spam. Just great engineering posts.

Enlaces y Navegación Imperativa

Así que hay dos casos para cambiar una ruta. Declarativamente, utilizando elementos , e imperativamente, llamando directamente a la API de enrutamiento (y, por tanto, de ubicación).
Angular
<h1> Shoutboard Application </h1>
<nav>
  <a routerLink="/home" routerLinkActive="active">Home</a>
  <a routerLink="/posts" routerLinkActive="active">Posts</a>
</nav>
<router-outlet></router-outlet>
Angular Router detecta automáticamente qué routerLink está activo, y pone una clase apropiadarouterLinkActive en ella, para que pueda ser estilizada.
El enrutador utiliza el elemento especial  para representar cualquier ruta de acceso actual. Es posible tener muchos ‘`, mientras profundizamos en los subcomponentes de la aplicación.
@Injectable()
export class FormService {
  constructor(private router: Router) { }
  goBack() {
    this.router.navigate(['/posts'])
  }
}
El módulo de enrutador puede ser inyectado a cualquier servicio (mitad-mágicamente por su tipo TypeScript), la declaración private lo almacena en la instancia sin necesidad de asignación explícita. Utilice el método navigate para cambiar las URL.
React
import * as style from './app.css'
// …
  

Shoutboard Application</h1>
Home Posts
{this.props.children}

React Router también puede establecer la clase de enlace activo con activeClassName.
Aquí no podemos proporcionar el nombre de la clase directamente porque se ha hecho único por el compilador de módulos CSS, y tenemos que usar el ayudante style. Hablaremos sobre eso más tarde.
Como se ha visto anteriormente, React Router utiliza el elemento  dentro de un elemento . Como el elemento simplemente envuelve y monta la ruta actual, significa que las sub-rutas del componente actual son simplemente this.props.children. Así que es componible también.
export class FormStore {
  routerStore: RouterStore
  constructor() {
    this.routerStore = RouterStore.getInstance()
  }
  goBack = () => {
    this.routerStore.history.push('/posts')
  }
}
El paquete mobx-router-store también permite una fácil inyección y navegación.
Resumen: Ambos enfoques de enrutamiento son bastante comparables. Angular parece ser más intuitivo, mientras que React Router tiene un poco más fácil de componer.

Inyección de Dependencia

Ya se ha demostrado que es beneficioso separar la capa de datos de la capa de presentación. Lo que estamos tratando de lograr con DI es hacer que los componentes de las capas de datos (aquí denominados modelo/tienda/servicio) sigan el ciclo de vida de los componentes visuales y, por lo tanto, permitan hacer una o varias instancias de dichos componentes sin necesidad de tocar globales estado. Además, debería ser posible mezclar y combinar datos compatibles y capas de visualización.
Ejemplos en este artículo son muy simples, por lo que todas las cosas DI puede parecer exceso, pero viene muy bien a medida que crece la aplicación.
Angular
@Injectable()
export class HomeService {
  message = 'Welcome to home page'
  counter = 0
  increment() {
    this.counter++
  }
}
Así que cualquier clase se puede hacer @inyectable, y sus propiedades y métodos puestos a disposición de los componentes.
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  providers: [
    HomeService
  ]
})
export class HomeComponent {
  constructor(
    public homeService: HomeService,
    public appService: AppService,
  ) { }
}
Al registrar el HomeService aproviders del componente, lo ponemos a disposición de este componente exclusivamente. No es un semifallo ahora, pero cada instancia del componente recibirá una nueva copia, fresca en el montaje del componente. Eso significa que no hay datos obsoletos de uso previo.
Por el contrario, el AppService se ha registrado en elapp.module (ver arriba), por lo que es un semifallo y se mantiene igual para todos los componentes, aunque la duración de la aplicación. Ser capaz de controlar el ciclo de vida de los servicios de los componentes es un concepto muy útil, pero poco apreciado.
DI funciona asignando las instancias de servicio al constructor del componente, identificadas por tipos TypeScript. Además, las palabras clave public asignan automáticamente los parámetros athis, de modo que ya no necesitamos escribir esas líneas aburridas this.homeService = homeService.
<div>
  <h3>Dashboard</h3>
  <md-input-container>
    <input mdInput placeholder='Edit your name' [(ngModel)]='appService.username' />
  </md-input-container>
  <br/>
  <span>Clicks since last visit: {{homeService.counter}}</span>
  <button (click)='homeService.increment()'>Click!</button>
</div>
Sintaxis de la plantilla de Angular, sin duda bastante elegante. Me gusta el atajo [()], que funciona como un enlace de datos de 2 vías, pero bajo el capó, en realidad es un atributo vinculante + evento. Como dicta el ciclo de vida de nuestros servicios, homeService.counterva a reiniciarse cada vez que naveguemos lejos de/home, pero el appService.usernamepermanece, y es accesible desde cualquier lugar.
React
import { observable } from 'mobx'
 
export class HomeStore {
  @observable counter = 0
  increment = () => {
    this.counter++
  }
}
Con MobX, necesitamos agregar el decorador @observable a cualquier propiedad que queramos hacer observable.
@observer
export class Home extends React.Component {
 
  homeStore: HomeStore
  componentWillMount() {
    this.homeStore = new HomeStore()
  }
 
  render() {
    return <Provider homeStore={this.homeStore}>
      <HomeComponent />
    </Provider>
  }
}
Para gestionar el ciclo de vida correctamente, necesitamos hacer un poco más de trabajo que en el ejemplo Angular. Envolvemos el HomeComponent dentro de unProvider, que recibe una nueva instancia de HomeStore en cada montaje.
interface HomeComponentProps {
  appStore?: AppStore,
  homeStore?: HomeStore
}
 
@inject('appStore', 'homeStore')
@observer
export class HomeComponent extends React.Component {
  render() {
    const { homeStore, appStore } = this.props
    return <div>
      <h3>Dashboard</h3>
      <Input
        type='text'
        label='Edit your name'
        name='username'
        value={appStore.username}
        onChange={appStore.onUsernameChange}
      />
      <span>Clicks since last visit: {homeStore.counter}</span>
      <button onClick={homeStore.increment}>Click!</button>
    </div>
  }
}
HomeComponent utiliza el decorador @observer para escuchar los cambios en las propiedades @observable.
El mecanismo bajo-la-capucha de esto es bastante interesante, así que vamos a pasar por esto brevemente aquí. El decorador @observable reemplaza una propiedad en un objeto con getter y setter, lo que le permite interceptar llamadas. Cuando se llama a la función render de un componente aumentado @observador, las propiedades getters se llaman y mantienen una referencia al componente que las llama.
A continuación, cuando se llama a setter y se cambia el valor, se llaman las funciones render de los componentes que utilizaron la propiedad en el último procesamiento. Ahora, los datos sobre qué propiedades se utilizan donde se actualizan, y todo el ciclo puede comenzar de nuevo.
Un mecanismo muy simple, y bastante performant también. Más explicación en profundidad aquí.
El decorador @inyectar 'se utiliza para inyectar instanciasappStoreyhomeStoreen los accesorios deHomeComponent. En este punto, cada una de esas tiendas tiene un ciclo de vida diferente.appStorees el mismo durante la vida de la aplicación, perohomeStore` es recién creado en cada navegación a la ruta “/home”.
La ventaja de esto es que no es necesario limpiar las propiedades manualmente, como ocurre cuando todas las tiendas son globales, lo cual es doloroso si la ruta es alguna página de “detalle” que contiene datos completamente diferentes cada vez.
Resumen: Como la gestión del ciclo de vida del proveedor en una característica inherente de la DI de Angular, es, por supuesto, más simple lograrlo allí. La versión de React es también utilizable pero implica mucho más boilerplate.

Propiedades Calculadas

React
Comencemos con Reaccionar en éste, tiene una solución más directa.
import { observable, computed, action } from 'mobx'
 
export class HomeStore {
import { observable, computed, action } from 'mobx'
 
export class HomeStore {
  @observable counter = 0
  increment = () => {
    this.counter++
  }
  @computed get counterMessage() {
    console.log('recompute counterMessage!')
    return `${this.counter} ${this.counter === 1 ? 'click' : 'clicks'} since last visit`
  }
}
Así que tenemos una propiedad calculada que se une a counter y devuelve un mensaje correctamente pluralizado. El resultado de counterMessage se almacena en caché y se vuelve a calcular sólo cuandocounter cambia.
<Input
  type='text'
  label='Edit your name'
  name='username'
  value={appStore.username}
  onChange={appStore.onUsernameChange}
/>
<span>{homeStore.counterMessage}</span>
<button onClick={homeStore.increment}>Click!</button>
Luego, hacemos referencia a la propiedad (y el método increment) de la plantilla JSX. El campo de entrada se controla mediante la vinculación a un valor y permite que un método de `appStore ‘maneje el evento de usuario.
Angular
Para lograr el mismo efecto en Angular, necesitamos ser un poco más inventivos.
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
 
@Injectable()
export class HomeService {
  message = 'Welcome to home page'
  counterSubject = new BehaviorSubject(0)
  // Computed property can serve as basis for further computed properties
  counterMessage = new BehaviorSubject('')
  constructor() {
    // Manually subscribe to each subject that couterMessage depends on
    this.counterSubject.subscribe(this.recomputeCounterMessage)
  }
 
  // Needs to have bound this
  private recomputeCounterMessage = (x) => {
    console.log('recompute counterMessage!')
    this.counterMessage.next(`${x} ${x === 1 ? 'click' : 'clicks'} since last visit`)
  }
 
  increment() {
    this.counterSubject.next(this.counterSubject.getValue() + 1)
  }
}
Necesitamos definir todos los valores que sirven como base para una propiedad calculada como un BehaviorSubject. La propia propiedad calculada es también un BehaviorSubject, porque cualquier propiedad calculada puede servir como entrada para otra propiedad calculada.
Por supuesto, RxJS puede hacer mucho másque sólo esto, pero eso sería un tema para un artículo completamente diferente. El inconveniente menor es que este uso trivial de RxJS para las propiedades calculadas es un poco más detallado que el ejemplo reactivo, y es necesario administrar las suscripciones manualmente (como aquí en el constructor).
<md-input-container>
  <input mdInput placeholder='Edit your name' [(ngModel)]='appService.username' />
</md-input-container>
<span>{{homeService.counterMessage | async}}</span>
<button (click)='homeService.increment()'>Click!</button>
Tenga en cuenta cómo podemos hacer referencia al sujeto RxJS con el |asíncrona . Eso es un toque agradable, mucho más corto que la necesidad de suscribirse en sus componentes. El componente input es impulsado por la directiva [(ngModel)]. A pesar de mirar extraño, es realmente bastante elegante. Sólo un azúcar sintáctico para la vinculación de datos de valor a appService.username y el valor de asignación automática del evento de entrada del usuario.
Resumen: Las propiedades calculadas son más fáciles de implementar en React/MobX que en Angular/RxJS, pero RxJS podría proporcionar algunas características de FRP más útiles, que podrían apreciarse más tarde.

Plantillas y CSS

Para mostrar cómo las pilas de plantillas entre sí, vamos a utilizar el componente de mensajes que muestra una lista de mensajes.
Angular
@Component({
  selector: 'app-posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css'],
  providers: [
    PostsService
  ]
})
 
export class PostsComponent implements OnInit {
  constructor(
    public postsService: PostsService,
    public appService: AppService
  ) { }
 
  ngOnInit() {
    this.postsService.initializePosts()
  }
}
Este componente sólo conecta HTML, CSS y servicios inyectados y también llama a la función para cargar los mensajes de la API en la inicialización. AppService es un semifallo definido en el módulo de aplicación, mientras quePostsService es transitorio, con una instancia nueva creada en cada componente de tiempo creado. El CSS que se hace referencia desde este componente tiene un ámbito de este componente, lo que significa que el contenido no puede afectar a nada fuera del componente.
<a routerLink="/form" class="float-right">
  <button md-fab>
    <md-icon>add</md-icon>
  </button>
</a>
<h3>Hello {{appService.username}}</h3>
<md-card *ngFor="let post of postsService.posts">
  <md-card-title>{{post.title}}</md-card-title>
  <md-card-subtitle>{{post.name}}</md-card-subtitle>
  <md-card-content>
    <p>
      {{post.message}}
    </p>
  </md-card-content>
</md-card>
En la plantilla HTML, hacemos referencia principalmente a componentes de Material Angular. Para tenerlos disponibles, era necesario incluirlos en las importaciones app.module(véase más arriba). La directiva *ngFor se utiliza para repetir el componente md-cardpara cada puesto.
Local CSS:
.mat-card {
  margin-bottom: 1rem;
}
El CSS local sólo aumenta una de las clases presentes en el componente md-card.
Global CSS:
.float-right {
  float: right;
}
Esta clase se define en el archivo global style.css para que esté disponible para todos los componentes. Se puede hacer referencia en la forma estándar, class =" float-right ".
Compiled CSS:
.float-right {
  float: right;
}
.mat-card[_ngcontent-c1] {
    margin-bottom: 1rem;
}
En CSS compilado, podemos ver que el CSS local ha sido delimitado al componente renderizado mediante el selector de atributos [_ngcontent-c1]. Cada componente Angular representado tiene una clase generada como ésta para fines de alcance CSS.
La ventaja de este mecanismo es que podemos referenciar clases normalmente, y el alcance se maneja “bajo el capó”.
React
import * as style from './posts.css'
import * as appStyle from '../app.css'
 
@observer
export class Posts extends React.Component {
 
  postsStore: PostsStore
  componentWillMount() {
    this.postsStore = new PostsStore()
    this.postsStore.initializePosts()
  }
 
  render() {
    return <Provider postsStore={this.postsStore}>
      <PostsComponent />
    </Provider>
  }
}
En React, de nuevo, necesitamos usar el métodoProvider para hacer que la dependencia de PostsStore sea “transitoria”. También importamos estilos CSS, denominados styley appStyle, para poder utilizar las clases de esos archivos CSS en JSX.
interface PostsComponentProps {
  appStore?: AppStore,
  postsStore?: PostsStore
}
 
@inject('appStore', 'postsStore')
@observer
export class PostsComponent extends React.Component {
  render() {
    const { postsStore, appStore } = this.props
    return <div>
      <NavLink to='form'>
        <Button icon='add' floating accent className={appStyle.floatRight} />
      </NavLink>
      <h3>Hello {appStore.username}</h3>
      {postsStore.posts.map(post =>
        <Card key={post.id} className={style.messageCard}>
          <CardTitle
            title={post.title}
            subtitle={post.name}
          />
          <CardText>{post.message}</CardText>
        </Card>
      )}
    </div>
  }
}
Naturalmente, JSX se siente mucho más JavaScript-y que las plantillas HTML de Angular, que puede ser una buena o mala cosa dependiendo de sus gustos. En lugar de la directiva *ngFor, usamos el constructomappara iterar sobre los posts.
Ahora bien, Angular podría ser el marco que promociona a TypeScript más, pero en realidad es JSX donde TypScript realmente brilla. Con la adición de módulos CSS (importados anteriormente), realmente convierte la codificación de su plantilla en zen de código. Cada cosa es revisada. Componentes, atributos, incluso clases CSS (appStyle.floatRight ystyle.messageCard, ver más abajo). Y, por supuesto, la naturaleza delgada de JSX fomenta la división en componentes y fragmentos un poco más que las plantillas de Angular.
Local CSS:
.messageCard {
  margin-bottom: 1rem;
}
Global CSS:
.floatRight {
  float: right;
}
Compiled CSS:
.floatRight__qItBM {
  float: right;
}
 
.messageCard__1Dt_9 {
    margin-bottom: 1rem;
}
Como puede ver, el cargador de CSS Módulos postfixes cada clase CSS con un postfix aleatorio, que garantiza la singularidad. Una forma sencilla de evitar conflictos. A continuación, las clases se hacen referencia a través de los objetos importados del paquete web. Un inconveniente posible de esto puede ser que no se puede crear un CSS con una clase y aumentarlo, como lo hicimos en el ejemplo Angular. Por otro lado, esto puede ser realmente una buena cosa, porque le obliga a encapsular estilos correctamente.
Resumen: Personalmente, me gusta JSX un poco mejor que las plantillas Angular, sobre todo debido a la terminación del código y el tipo de control de apoyo. Eso realmente es una característica asesina. Angular ahora tiene el compilador AOT, que también puede detectar algunas cosas, la finalización de código también funciona para alrededor de la mitad de las cosas allí, pero no es casi tan completo como JSX/TypeScript.

GraphQL - Cargando Datos

Así que hemos decidido utilizar GraphQL para almacenar datos para esta aplicación. Una de las maneras más fáciles de crear el back-end de GraphQL es usar algún BaaS, como Graphcool. Así que eso es lo que hicimos. Básicamente, sólo define modelos y atributos, y su CRUD es bueno para ir.
Código Común
Como parte del código relacionado con GraphQL es 100% igual para ambas implementaciones, no lo repetimos dos veces:
const PostsQuery = gql`
  query PostsQuery {
    allPosts(orderBy: createdAt_DESC, first: 5)
    {
      id,
      name,
      title,
      message
    }
  }
`
GraphQL es un lenguaje de consulta dirigido a proporcionar un conjunto más rico de funcionalidad en comparación con los puntos finales RESTful clásicos. Vamos a diseccionar esta consulta en particular.
  • PostsQuery es sólo un nombre para esta consulta a la referencia posterior, se puede nombrar nada.
  • allPosts es la parte más importante - hace referencia a la función para consultar todos los registros con el modelo `Post`. Este nombre fue creado por Graphcool.
  • orderBy y first son parámetros de la función allPosts. createdAt es uno de los Post atributos del modelo. first: 5significa que devolverá sólo los primeros 5 resultados de la consulta.
  • id, name, title, y message son los atributos del modelo Post que queremos ser incluidos en el resultado. Otros atributos serán filtrados.
Como ya puedes ver, es bastante potente. Echa un vistazo a esta página para familiarizarse más con las consultas de GraphQL.
interface Post {
  id: string
  name: string
  title: string
  message: string
}
 
interface PostsQueryResult {
  allPosts: Array
}
Sí, como buenos ciudadanos de TypeScript, creamos interfaces para los resultados de GraphQL.
Angular
@Injectable()
export class PostsService {
  posts = []
 
  constructor(private apollo: Apollo) { }
 
  initializePosts() {
    this.apollo.query({
      query: PostsQuery,
      fetchPolicy: 'network-only'
    }).subscribe(({ data }) => {
      this.posts = data.allPosts
    })
  }
}
La consulta GraphQL es un RxJS observable, y nos suscribimos a ella. Funciona un poco como una promesa, pero no es así, por lo que no tenemos suerte con async/await. Por supuesto, todavía hay toPromise, pero no parece ser el camino Angular de todas formas. Establecemos fetchPolicy: 'network-only'porque en este caso, no queremos almacenar en caché los datos, sino refetch cada vez.
React
export class PostsStore {
  appStore: AppStore
 
  @observable posts: Array = []
 
  constructor() {
    this.appStore = AppStore.getInstance()
  }
 
  async initializePosts() {
    const result = await this.appStore.apolloClient.query({
      query: PostsQuery,
      fetchPolicy: 'network-only'
    })
    this.posts = result.data.allPosts
  }
}
La versión de React es casi idéntica, pero como apolloClient aquí usa promesas, podemos aprovechar la sintaxisasync / await. Existen otros enfoques en React que sólo “graban” las consultas GraphQL a componentes de orden superior, pero me pareció mezclar la capa de datos y presentación a tad demasiado.
En resúmen: Las ideas de la RxJS suscribirse vs async/await son realmente lo mismo.

GraphQL - Guardando Datos

Código Común
Una vez más, algo de código GraphQL relacionado:
const AddPostMutation = gql`
  mutation AddPostMutation($name: String!, $title: String!, $message: String!) {
    createPost(
      name: $name,
      title: $title,
      message: $message
    ) {
      id
    }
  }
`
El propósito de las mutaciones es crear o actualizar registros. Por lo tanto, es beneficioso para declarar algunas variables con la mutación, ya que son la forma de cómo pasar los datos en ella. Así que tenemos las variables name,title y message, escritas como String, que necesitamos llenar cada vez que llamemos a esta mutación. La función createPost, de nuevo, está definida por Graphcool. Especificamos que las claves del modelo Posttendrán valores de las variables de mutación de salida, y también que queremos que elid del Post recién creado sea enviado a cambio.
Angular
@Injectable()
export class FormService {
  constructor(
    private apollo: Apollo,
    private router: Router,
    private appService: AppService
  ) { }
 
  addPost(value) {
    this.apollo.mutate({
      mutation: AddPostMutation,
      variables: {
        name: this.appService.username,
        title: value.title,
        message: value.message
      }
    }).subscribe(({ data }) => {
      this.router.navigate(['/posts'])
    }, (error) => {
      console.log('there was an error sending the query', error)
    })
  }
 
}
Cuando llamamos apollo.mutate, necesitamos proporcionar la mutación que llamamos y las variables también. Obtenemos el resultado en la función de devolución de llamada subscribe y usamos el` roteador ‘inyectado para navegar de nuevo a la lista de correos.
React
export class FormStore {
  constructor() {
    this.appStore = AppStore.getInstance()
    this.routerStore = RouterStore.getInstance()
    this.postFormState = new PostFormState()
  }
 
  submit = async () => {
    await this.postFormState.form.validate()
    if (this.postFormState.form.error) return
    const result = await this.appStore.apolloClient.mutate(
      {
        mutation: AddPostMutation,
        variables: {
          name: this.appStore.username,
          title: this.postFormState.title.value,
          message: this.postFormState.message.value
        }
      }
    )
    this.goBack()
  }
 
  goBack = () => {
    this.routerStore.history.push('/posts')
  }
}
Muy similar a lo anterior, con la diferencia de más “manual” la inyección de dependencia, y el uso de async/await.
En resúmen: Una vez más, no hay mucha diferencia aquí. suscribirse vs async / await es básicamente todo lo que difiere.

Formularios

Queremos lograr los siguientes objetivos con los formularios de esta aplicación:
  • Enlace de datos de campos a un modelo
  • Mensajes de validación para cada campo, varias reglas
  • Soporte para comprobar si todo el formulario es válido
React
export const check = (validator, message, options) =>
  (value) => (!validator(value, options) && message)
 
export const checkRequired = (msg: string) => check(nonEmpty, msg)
 
export class PostFormState {
  title = new FieldState('').validators(
    checkRequired('Title is required'),
    check(isLength, 'Title must be at least 4 characters long.', { min: 4 }),
    check(isLength, 'Title cannot be more than 24 characters long.', { max: 24 }),
  )
  message = new FieldState('').validators(
    checkRequired('Message cannot be blank.'),
    check(isLength, 'Message is too short, minimum is 50 characters.', { min: 50 }),
    check(isLength, 'Message is too long, maximum is 1000 characters.', { max: 1000 }),
  )
  form = new FormState({
    title: this.title,
    message: this.message
  })
}
Por lo tanto, la librería formstate funciona de la siguiente manera: para cada campo de su formulario, define un FieldState. El parámetro pasado es el valor inicial. La propiedad validators toma una función, que devuelve “false” cuando el valor es válido, y un mensaje de validación cuando el valor no es válido. Con las funciones de check' ycheckRequired`, todo puede parecer muy declarativo.
Para tener la validación de toda la forma, es beneficioso también envolver esos campos con una instancia FormState, que a continuación, proporciona la validez agregada.
@inject('appStore', 'formStore')
@observer
export class FormComponent extends React.Component {
  render() {
    const { appStore, formStore } = this.props
    const { postFormState } = formStore
    return <div>
      <h2> Create a new post </h2>
      <h3> You are now posting as {appStore.username} </h3>
      <Input
        type='text'
        label='Title'
        name='title'
        error={postFormState.title.error}
        value={postFormState.title.value}
        onChange={postFormState.title.onChange}
      />
      <Input
        type='text'
        multiline={true}
        rows={3}
        label='Message'
        name='message'
        error={postFormState.message.error}
        value={postFormState.message.value}
        onChange={postFormState.message.onChange}
      />
La instancia FormState proporciona propiedades value, onChange y error, que se pueden utilizar fácilmente con cualquier componente front-end.
      
} }
Cuando form.hasError estrue, mantenemos el botón deshabilitado. El botón Enviar envía el formulario a la mutación GraphQL presentada anteriormente.
Angular
En Angular, vamos a utilizar FormService y FormBuilder, que son partes del paquete @angular/forms.
@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  providers: [
    FormService
  ]
})
export class FormComponent {
  postForm: FormGroup
  validationMessages = {
    'title': {
      'required': 'Title is required.',
      'minlength': 'Title must be at least 4 characters long.',
      'maxlength': 'Title cannot be more than 24 characters long.'
    },
    'message': {
      'required': 'Message cannot be blank.',
      'minlength': 'Message is too short, minimum is 50 characters',
      'maxlength': 'Message is too long, maximum is 1000 characters'
    }
  }
First, let’s define the validation messages.
  constructor(
    private router: Router,
    private formService: FormService,
    public appService: AppService,
    private fb: FormBuilder,
  ) {
    this.createForm()
  }
 
  createForm() {
    this.postForm = this.fb.group({
      title: ['',
        [Validators.required,
        Validators.minLength(4),
        Validators.maxLength(24)]
      ],
      message: ['',
        [Validators.required,
        Validators.minLength(50),
        Validators.maxLength(1000)]
      ],
    })
  }
Usando FormBuilder, es muy fácil crear la estructura del formulario, aún más sucintamente que en el ejemplo React.
  get validationErrors() {
    const errors = {}
    Object.keys(this.postForm.controls).forEach(key => {
      errors[key] = ''
      const control = this.postForm.controls[key]
      if (control && !control.valid) {
        const messages = this.validationMessages[key]
        Object.keys(control.errors).forEach(error => {
          errors[key] += messages[error] + ' '
        })
      }
    })
    return errors
  }
Para obtener mensajes de validación vinculables en el lugar correcto, necesitamos realizar algún procesamiento. Este código se toma de la documentación oficial, con algunos pequeños cambios. Básicamente, en FormService, los campos guardan referencia sólo a errores activos, identificados por nombre de validador, por lo que necesitamos emparejar manualmente los mensajes requeridos a los campos afectados. Esto no es totalmente un inconveniente; por ejemplo, se presta más fácilmente a la internacionalización.
  onSubmit({ value, valid }) {
    if (!valid) {
      return
    }
    this.formService.addPost(value)
  }
 
  onCancel() {
    this.router.navigate(['/posts'])
  }
}
Una vez más, cuando el formulario es válido, los datos pueden ser enviados a la mutación GraphQL.
<h2> Create a new post </h2>
<h3> You are now posting as {{appService.username}} </h3>
<form [formGroup]="postForm" (ngSubmit)="onSubmit(postForm)" novalidate>
  <md-input-container>
    <input mdInput placeholder="Title" formControlName="title">
    <md-error>{{validationErrors['title']}}</md-error>
  </md-input-container>
  <br>
  <br>
  <md-input-container>
    <textarea mdInput placeholder="Message" formControlName="message"></textarea>
    <md-error>{{validationErrors['message']}}</md-error>
  </md-input-container>
  <br>
  <br>
  <button md-raised-button (click)="onCancel()" color="warn">Cancel</button>
  <button
    md-raised-button
    type="submit"
    color="primary"
    [disabled]="postForm.dirty && !postForm.valid">Submit</button>
  <br>
  <br>
</form>
Lo más importante es hacer referencia al formGroup que hemos creado con FormBuilder, que es la asignación [formGroup] = 'postForm'. Los campos dentro del formulario están enlazados al modelo de formulario a través de la propiedad formControlName. Nuevamente, desactivamos el botón “Enviar” cuando el formulario no es válido. También debemos agregar el check sucio, porque aquí, el formulario no sucio puede ser inválido. Queremos que el estado inicial del botón esté “habilitado”.
En resúmen: Este enfoque de las formas en React y Angular es bastante diferente en los frentes de validación y de plantilla. El enfoque Angular implica un poco más de “magia” en lugar de un enlace directo, pero, por otro lado, es más completo.

Tamaño del Lote

Oh, una cosa más. La producción redujo los tamaños de paquetes de JS, con ajustes por defecto de los generadores de aplicación: notablemente Tree Shaking en React y AOT compilación en Angular.
  • Angular: 1200 KB
  • React: 300 KB
Bueno, no hay mucha sorpresa aquí. Angular siempre ha sido el más voluminoso.
Cuando se utiliza gzip, los tamaños bajan a 275kb y 127kb respectivamente.
Sólo ten en cuenta que estas son básicamente todas las librerías de proveedores. La cantidad de código de aplicación real es mínima por comparación, lo que no es el caso en una aplicación del mundo real. Allí, la proporción sería probablemente más parecida a 1:2 que 1:4. Además, cuando empieces a incluir muchas librerías de terceros con React, el tamaño del paquete también tiende a crecer con bastante rapidez.

Flexibilidad de las bibliotecas frente a la robustez del marco

Así que parece que no hemos sido capaces (¡de nuevo!) para dar una respuesta clara sobre si Angular o React es mejor para el desarrollo web.
Resulta que los flujos de trabajo de desarrollo en React y Angular pueden ser muy similares, dependiendo de las bibliotecas que elegimos para usar React with. Entonces es principalmente una cuestión de preferencia personal.
Si te gustan las pilas ya hechas, la poderosa inyección de dependencia y el plan para usar algunas golosinas de RxJS, eligió Angular.
Si te gusta jugar y construir tu propia pila, te gusta la simplicidad de JSX y prefieres propiedades computables más simples, selecciona React / MobX.
Una vez más, puede obtener el código fuente completo de la aplicación de este artículo aquí yaquí.
O, si prefieres ejemplos más grandes, y de RealWorld:

Primero, Elige tu Paradigma de Programación

La programación con React/MobX es en realidad más similar a Angular que con React/Redux. Hay algunas diferencias notables en las plantillas y el manejo de dependencias, pero tienen el mismo paradigma mutable/data binding.
React / Redux con su paradigmainmutable/unidireccional es una bestia completamente diferente.
No te dejes engañar por la pequeña huella de la librería de Redux. Puede ser pequeña, pero es un framework de todos modos. La mayoría de las mejores prácticas de Redux hoy se centran en el uso de librerías compatibles con redux, comoRedux Saga para el código asíncrono y la búsqueda de datos, Redux Form para la gestión de formularios, Reselect para selectores memorizados (valores calculados de Redux). yRecompose, entre otros, para una gestión del ciclo de vida más fina. Además, hay un cambio en la comunidad Redux de Immutable.js aRamda o lodash/fp, que funcionan con objetos JS sencillos en lugar de convertirlos.
Un buen ejemplo de Redux moderno es el bien conocido React Boilerplate. Es una pila de desarrollo formidable, pero si lo echas un vistazo, es realmente muy, muy diferente de todo lo que hemos visto en este post hasta ahora.
Siento que Angular está recibiendo un poco de tratamiento injusto de la parte más vocal de la comunidad de JavaScript. Muchas personas que expresan su insatisfacción con ella probablemente no aprecian el cambio inmenso que ocurrió entre el antiguo AngularJS y Angular de hoy. En mi opinión, es un marco muy limpio y productivo que tomaría el mundo por la tormenta si hubiera aparecido 1-2 años antes.
Sin embargo, Angular está ganando un punto de apoyo sólido, especialmente en el mundo corporativo, con grandes equipos y necesidades de estandarización y soporte a largo plazo. O para decirlo de otra manera, Angular es la forma en que los ingenieros de Google piensan que el desarrollo web debe hacerse, si eso sigue siendo así.
En cuanto a MobX, se aplica una evaluación similar. Realmente genial, pero no se aprecia mucho.
En conclusión: antes de elegir entre React y Angular, elige primero tu paradigma de programación.
mutable/enlace de datos óinmutable/unidireccional, ese parece ser el problema real.

El articulo original lo puede ver en el siguiente enlace.