Saltar al contenido

Evaluar las herramientas de desarrollo web de React vs. Angular 2

Angular 2

Angular 2 está escrito en TypeScript, un lenguaje superconjunto de JavaScript desarrollado por Microsoft. El lenguaje introduce tipos, nuevas estructuras de datos y más características orientadas a los objetos, haciendo el código más fácil de leer y mantener comparado con el JavaScript de vainilla. Inicialmente, la sintaxis de TypeScript fue pensada para ser una reminiscencia de C#. Sin embargo, los recientes verios de TypeScript presentan la notación de flecha (=>) y otra sintaxis específica de ES6, haciendo que el TS se parezca más a ES6.

El uso de TypeScript hace que configurar una aplicación Angular 2 sea algo tedioso, ya que introduce una sobrecarga extra para la configuración.

Evaluar las herramientas de desarrollo web de React vs. Angular 2
Evaluar las herramientas de desarrollo web de React vs. Angular 2

Reaccionar

React se basa en JSX (Java Serialization to XML), una extensión de sintaxis XML para renderizar JavaScript y HTML. En términos de sintaxis y estructura, JSX se parece a JavaScript y parece que se mezcla con HTML más fácilmente. Permite la mezcla de variables y estructuras de datos de JavaScript dentro del marcado HTMl.

Para obtener una comparación más clara entre las estructuras de código de React y Angular 2, vamos a comparar cómo se construye una aplicación básica de TODO (aplicaciones de ejemplo construidas por Mark Volkmann (mvolkmann).

Ambas aplicaciones utilizan Webpack para el desarrollo y el despliegue.

En términos de estructura de la aplicación, tanto React como Angular 2 necesitan dos archivos – TodoList que representa la lista de tareas y Todo que representa una sola tarea.

Analicemos el componente TodoList ( todolist.component.ts para Angular 2 y todo-list.js para Reaccionar, respectivamente) pieza por pieza, de arriba a abajo:

Importación

Angular 2
123importar{Componente}de$0027@angular/núcleo$0027;importar{bootstrap}de$0027@angular/plataforma-browser-dinámico$0027;;importar{TodoCmp,ITodo}de"./todoCmp";

ts

Reaccionar
123importReactfrom "react";importReactDOMfrom "react-dom";importTodofrom"./todo";

js

Inicialización de un componente

He detectado las diferencias clave entre las herramientas usando comentarios.

Angular 2
1234567891011121314151617181920212223242526272829// Se utiliza para el tipo de propiedad estatal en la clase TodoListCmp.// Ambas propiedades son opcionales, pero se prefieren ya que hacen// el código más mantenible.interfaceIState{ todos?:ITodo[]; todoText?: string;}// Esta sintaxis se llama Decorador y es similar// a las Anotaciones en otros idiomas. Los decoradores están// bajo consideración para ser incluidos en ES2016.@Componente({ selector:$0027todo-lista$0027, plantilla:``/*Aquí es donde se puede poner el marcado para la plantilla. Alternativamente, puede hacer referencia a un archivo html usando templateUrl */})exportclassTodoListCmp{privatestatic lastId: number =0;private state:IState;constructor(){this.state={ todos:[TodoListCmp.createTodo($0027learn Angular$0027,true),TodoListCmp.createTodo($0027build an Angular app$0027)]};}

js

Reaccionar
123456789101112let lastId =0;// no hay propiedades de clase estáticas en ES6classTodoListextendsReact.Componente{constructor(){super();// debe llamar antes de acceder a "this "this.state={ todos:[TodoList.createTodo($0027learn React$0027,true),TodoList.createTodo($0027build a React app$0027)]};}

js

Creación de un elemento

Angular 2
1234567891011estaticcreateTodo( text:string, done_boolean=false):ITodo{retorno{id:++TodoListCmp.lastId, text, done};}onAddTodo():void{const newTodo_ITodo=TodoListCmp. createTodo(this.state.todoText);this.state.todoText=$0027$0027;this.state.todos=this.state.todos.concat(newTodo);}

ts

Reaccionar
123456789101112estaticcreateTodo(text, done =false){retorno{id:++TodoList.lastId, text, done};}onAddTodo(){const newTodo =TodoList. createTodo(this.state.todoText);this.setState({ todoText:$0027$0027, todos:this.state.todos.concat(newTodo)});}

js

Como se ha visto anteriormente, el proceso de creación es bastante similar para ambas herramientas, pero la de React es ligeramente más corta y parece necesitar menos lógica de desarrollo.

Detección de los estados de los artículos

Angular 2
12345getuncompletedCount(): number {returnthis.state.todos.reduce((count: number, todo:ITodo)=> todo.done? count : count +1,0);}

js

Reaccionar
12345getuncompletedCount(){retorno.state.todos.reduce((count, todo)=> todo.done? count : count +1,0);}

js

Reaccionando a los cambios

Angular 2
1234567891011121314151617181920enArchivoCompletado():void{this.state.todos=this.state.todos.filter((t:ITodo)=>!t.done);}enCambiar(newText: cadena):void{this.state.todoText= newText;}enBorrarTodo(todoId: número):void{this.state. todos=este.estado.todos.filtro((t:ITodo)={; t.id!== todoId);}onToggleDone(todo:ITodo):void{const id: número = todo. id;this.state.todos=this.state.todos.map((t:ITodo)=> t.id=== id ?{id, text: todo.text, done:!todo.done}: t);}

js

Reaccionar
12345678910111213141516171819202122232425enArchivoCompletado(){esto.setState({ todos:este.estado.todos.filtro(t=§;!t.hecho)});}enCambiar(nombre, evento){esto.setState({[nombre]: evento.valor.objetivo});}enBorrarTodo(todoId){esto. setState({ todos:this.state.todos.filter(t= > t.id!== todoId)});}onToggleDone(todo){const id = todo.id;const todos =this. state.todos.map(t=> t.id=== id ?{id, text: todo.text, done:!todo.done}: t);this.setState({todos});}

js

Bootstrapping

Angular 2
12345678910111213///En Angular 2, los trozos de la// lógica de aplicación responsables de una determinada característica// están encapsulados en un móduloimport{NgModule}de"@angular/núcleo";import{BrowserModule}de"@angular/plataforma-browser";import{TodoListCmp}de". /todoList.component";@NgModule({ importa:[BrowserModule], declaraciones:[TodoListCmp], bootstrap:[TodoListCmp]})exportclassAppModule{}//An Angular module puede importar funcionalidades de otros módulos y exportar algunos de sus bloques de construcción a otros módulos.

js

123456789// src/main.tsimport{ platformBrowserDynamic }from"@angular/plataforma-browser-dynamic";import{AppModule}from"./app.module";// El módulo se arranca, haciendo que el componente arrancado sea la raíz // de la aplicación si no se definen rutas.const platform =platformBrowserDynamic();platform.bootstrapModule(AppModule);

js

Reaccionar
123456789}// fin de la clase TodoList// Esto hace que un componente de TodoList// dentro de un elemento DOM especificado.// Si TodoList se usara en más de un lugar,// se movería a un archivo JavaScript diferente.ReactDOM.render(<TodoList/;,document.getElementById($0027contenedor$0027));

js

Sintaxis de la plantilla

Angular 2
12345678910111213141516171819202122232425262728293031323334353637383940414243 // Este es el valor de la plantilla @Componente // propiedad arriba. Fue movido aquí para // una fácil comparación con el método de renderización de React. `<div>h2;³ To Do List</h2;div;³; {{{uncompletedCount}} de {{state.todos.length}} que queda <!-- Al hacer clic en este botón se invoca el método de componentes enArchivoCompletado. --;-- button(click)="onArchiveCompleted()"``; Archive Completed </button;--[ngModel] dice dónde obtener el valor. --¡¡Botón!! -- [ngModel] dice qué hacer en el cambio de valor. --[[]-- (inputtype="text "size="30 "autoFocusplaceholder="enter new todo here"[ng-model]="state.todoText"(input)="onChange($event.target. valor)"/[;botón[desactivado]="!state.todoText"(click)="onAddTodo()"> Add </button </form><ul><!-- Esto usa un bucle for para generar TodoCmps. #todo define una variable para usar dentro del bucle. [todo] establece una propiedad en cada TodoCmp. (onDeleteTodo) y (onToggleDone) son salidas del TodoCmp, y llaman a funciones en TodoListCmp con valores emitidos. deleteTodo recibe un tipo de número. toggleDone recibe un tipo de ITodo. --;<todo*ngFor="let todo of state.todos"[todo]="todo"(on-delete-todo)="onDeleteTodo($event)"(on-toggle-done)="onToggleDone($event)"

html

Reaccionar
12345678910111213141516171819202122232425262728293031323334353637render(){// Puede asignar parte de la UI// generada a una variable y referirse a ella más tarde.const todos =this.state.todos.map(todo=§;<Todo key={todo. id} todo={todo} onDeleteTodo={this.onDeleteTodo.bind(this, todo.id)} onToggleDone={this.onToggleDone. bind(this, todo)}/;);return(<div)};h2;ToDoList</h2;div;};{esta.cuenta.incompleta}de{este.estado.todos. longitud} restante} botón onClick={()=.this.onArchivoCompletado()}{archivoCompletado</botón&÷;br/b/b1;form====tipo de entrada="texto" size="30" autoFocus placeholder="introducir nuevo todo aquí" value={this.state. todoText} onChange={e===;this.onChange($0027todoText$0027, e)}/mph;<button disabled={!this.state.todoText} onClick={()=[;this. onAddTodo()};Add</button &gt >/formform----;ul className="unstyled"³;{todos}</ul>/div;);}

js

El código de componentes de Angular 2 es generalmente más verboso que el de React. El único caso que hemos cubierto donde React requiere más código es con el bootstrapping. Esta disparidad puede ser atribuida a TypeScript. :void , :ITodo y otros tipos se ven a menudo en el TypeScript. El estilo Angular 2 usualmente dicta que las variables, los parámetros de la función y la función misma deben tener un tipo en TypeScript. React no tiene nada de eso, haciendo el código más conveniente para los desarrolladores que prefieren el tradicional y más suculento JavaScript.

Angular 2 utiliza decoradores @Componente para especificar las diferentes construcciones (servicios, directivas, tuberías) que contiene y para definir sus propias propiedades. También permite al desarrollador especificar un selector para el componente y poner el código para la plantilla usando la propiedad de la plantilla o la plantillaUrl si se usa un archivo separado. Lo mismo se aplica a los estilos – hay una opción para introducir estilos directamente usando la propiedad styles o para incluir un array de archivos usando styleUrls. React no tiene un análogo para un decorador de componentes y requiere que la plantilla del componente se incluya en el propio archivo del componente, lo que limita las opciones de personalización y hace que la información sobre un componente sea más difícil de interpretar.

Las plantillas de Angular 2 vienen con una convención específica para los diferentes elementos:

  • * denota una directiva que manipula el DOM. Por ejemplo, *ngFor itera sobre un conjunto de valores y crea un nuevo elemento para cada uno. *ngIf se usa para denotar si un elemento puede ser visto o no.
  • [] denota una propiedad vinculante, indicando que el elemento recibe un valor del componente. Se utiliza principalmente para pasar datos a un componente hijo al padre.
  • () indica una unión de eventos (como (clic), que desencadena una función en los componentes.
  • [()] indica una unión de dos vías, lo que significa que cualquier cambio en los datos que se pasen se propagará.

Las plantillas de reacción también tienen sus peculiaridades. JSX difumina la línea por HTML y JavaScript, proporcionando su propio marcado. Aunque parece que la plantilla está escrita en HTML, el marcado es en realidad XML que luego es analizado en HTML. Debido a JSX, las palabras de propiedad HTML estándar están en mayúsculas o tienen nombres diferentes – onclick en JSX es onClick. for (usado en etiquetas) se convierte en htmlFor porque for es una palabra reservada en JavaScript (que significa for-loop).

Componentes de anidación

A continuación, veamos cómo se ve el componente para un solo artículo de ToDo en Angular 2 y en Reaccionar:

Angular 2
1234567891011121314151617181920212223242526272829303132333435363738394041importación{Componente,entrada,salida,emisor de eventos}de$0027angular2/angular2$0027;exportacióntinterfazITodo{id: número; texto: cadena; hecho: booleano;}@Componente({ selector:$0027todo$0027, plantilla:` <li> <tipo de entrada="casilla de verificación" [marcado]="todo". done" (change)="toggleDone()"/ > <span [ng-class]="$0027done-$0027 + todo.done"> {{{todo.text}}} </span> <button (click)="deleteTodo()">Delete</button> </li>`})exportclassTodoCmp{// @Input permite a este componente recibir/// valores de inicialización del componente que lo contiene. @Input() todo:ITodo;// @Output permite a este componente recibir/// publicar valores del componente que lo contiene. @Output() onDeleteTodo:EventEmitter<número;=newEventEmitter<número;// @Output() onToggleDone:EventEmitter<ITodo;// =newEventEmitter<ITodo;// deleteTodo():void{this. onDeleteTodo.next(this.todo.id);}toggleDone():void{this.onToggleDone.next(this.todo);}}

js

Reaccionar
123456789101112131415161718192021222324importReactfrom "reaccionar"// Hay tres formas de definir los componentes de Reaccionar.// Esta es la forma de componente de función sin estado// que sólo recibe datos a través de "props". // Un objeto de props se pasa a esta función// y desestructurado.constTodo=(onDeleteTodo, onToggleDone, todo })={;(<li><input type="checkbox" checked={todo. done} onChange={onToggleDone}/;<span className={"done-"+ todo.done};{todo.text}</span><botón onClick={onDeleteTodo};Delete</button constPropTypes=React.PropTypes;Todo.propTypes={ todo:PropTypes.object.isRequired, onDeleteTodo:PropTypes.func.isRequired, onToggleDone:PropTypes.func.isRequired};exportdefaultTodo;

js

Debido a que es el principal componente de una aplicación de React, el componente ofrece una mayor flexibilidad en la forma en que puede ser estructurado. Los componentes sin estado se construyen teniendo en cuenta el flujo de datos unidireccional, dejando la mayor parte de la lógica fuera del propio componente. Angular 2 también ofrece una funcionalidad similar, pero lo hace con más complejidad.