React

React

In questo post parleremo di React: nuova libreria, creata da Facebook, da utilizzare nel front-end di applicazioni web. Si pone come diretto concorrente di AngularJS e soprattutto del futuro AngularJS 2. Implementeremo insieme la classica todo-list per cercare di capire insieme quali sono le principali caratteristiche di queste nuove API.

Caratteristiche

Uno dei concetti più interessanti di React è il virtual DOM: tutte le operazioni che React effettua sul DOM vengono in realtà “parcheggiate” in un DOM virtuale in memoria che fa da specchio a quello reale, alla fine di ogni ciclo di render vengono trasportate sul DOM reale esclusivamente le modifiche minime necessarie per allineare i due DOM. Questo meccanismo permette a React di essere estremamente efficiente.

Un’altra caratteristica interessante di React è quello di essere isomorfico, può essere cioè eseguito indifferente su un browser o su di un server Node.js, in questo modo si evita uno dei problemi maggiori di framework front-end complessi come AngularJS: l’assenza di indicizzazione da parte dei motori di ricerca. Infatti con React è possibile effettuare il primo render della pagina tramite il server e tutte le interazioni successive con il browser. In questo modo gli spider di Google sono in grado di analizzare il contenuto di una pagina e calcolare il PageRank del nostro sito. D’altro canto un’applicazione AngularJS non contiene informazioni fintanto che l’applicazione stessa non è completamente caricata e questo rende difficile agli spider l’analisi del sito.

Setup del progetto

Vediamo subito la index della nostra applicazione:

<html>
  <head>
    <title>React Todo-list</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="https://fb.me/react-0.13.3.js"></script>
    <script src="https://fb.me/JSXTransformer-0.13.3.js"></script>
    <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
    <link rel="icon" href="favicon.ico" type="image/x-icon"/>
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
  </head>
  <body>
    <div id="wrapper">

    </div>
    <script src="js/TodoRepository.js"></script>
    <script type="text/jsx" src="js/TodoApp.js"></script>
    <script type="text/jsx" src="js/TodoForm.js"></script>
    <script type="text/jsx" src="js/TodoList.js"></script>
    <script type="text/jsx" src="js/Todo.js"></script>
    <script type="text/jsx">
      React.render(<TodoApp/>,document.getElementById('wrapper'));
    </script>
  </body>
</html>

Due sono le cose da notare nell’indice: l’import del JSXTransformer e la presenza di script di tipo text/jsx. JSX è un estensione del JavaScript che permettere di aggiungere codice HTML all’interno di file di codice. Il JSXTransformer compila a runtime i file JSX in file Javascript puro compatibili con i browser, questa trasformazione è molto onerosa quindi è indispensabile una fase di deploy in produzione, nella quale tramite il tool react-tools potete effettuare questa trasformazione in modalità off-line guadagnando in velocità.

Componenti

L’unica riga di codice all’interno della nostra index è la seguente:

React.render(<TodoApp/>,document.getElementById('wrapper'));

Che non fa altro che aggiungere il componente TodoApp all’interno del div wrapper visto nell’index. Questa riga ci fa intuire la caratterista principe di React: ogni applicazione è composta esclusivamente da componenti, compresa l’applicazione stessa. Analizziamo l’elemento Todo, il tassello più piccolo della nostra todo-list.

var Todo = React.createClass({
  onDeleteClick:function(){
  	this.props.onDeleteCallback(this.props.value);
  },
  render: function() {
    return (
      <tr>
        <td>
      	{this.props.value}
        <button className="pull-right btn btn-default" onClick={this.onDeleteClick}>
          Done
        </button>
        </td>
      </tr>
    );
  }
});

Ecco in pratica l’utilizzo di JSX, ci permette di creare delle classi di React che contengono contemporaneamente business logic e markup. Per quanto possa sembrare un anti-pattern in realtà funziona se i componenti creati sono autoconsistenti. In questo modo sono facilmente testabili e mantenibili. Questi componenti possono essere facilmente composti tra di loro come possiamo vedere nel prossimo componente: la TodoList.

var TodoList = React.createClass({
	render: function() {
		var items = this.props.data.map(function(todo,i) {
			return (<Todo key={i} onDeleteCallback={this.props.onDeleteCallback} value={todo}></Todo>);
		},this);
		return (<table className="table">{items}</table>);
	}
});

Come vedete la TodoList non è nient’altro che una <table> con all’interno dei Todo (che a loro volta erano delle <tr>). In entrambi gli esempi è presente l’oggetto props che contiene gli attributi dei vari componenti (data in questo caso, value e onDeleteCallback nel caso precedente).

Passiamo ora alla form di inserimento di un nuovo elemento:

var TodoForm = React.createClass({
	saveTodo:function(){

		var inputComponent = React.findDOMNode(this.refs.todoInput);

		this.props.onSave(inputComponent.value);

		inputComponent.value = "";
	},
	render: function() {
		return (
			<div className="container">
			  <div className="row">
			  	<div className="col-sm-8">
			  		<input type="text" className="form-control" id="textInput" ref="todoInput" placeholder="Add Todo..."/>
			  	</div>
			  	<div className="col-sm-4">
			  		<button className="btn btn-default" onClick={this.saveTodo}>
			  			Save
			  		</button>
			  	</div>
			  </div>
			</div>
		);
	}
});

In questo caso abbiamo bisogno di recuperare il valore da un <input> e per farlo dobbiamo utilizzare l’attributo ref e la funzione React.findDOMNode.

Ultimo componente da analizzare è la TodoApp stessa:

var TodoApp = React.createClass({
  getInitialState: function() {
  	return {data: todoRepository.list()};
  },
  onSave:function(todo){
    this.setState({data:todoRepository.store(todo)});
  },
  onDelete:function(todo){
    this.setState({data:todoRepository.delete(todo)});
  },
  render: function() {
    return (
    	<div>
    		<h1 className="text-center">TodoApp</h1>
        <TodoForm onSave={this.onSave}/>
        <hr/>
    		<TodoList onDeleteCallback={this.onDelete} data={this.state.data}/>
    	</div>
    );
  }
});

In questo componente possiamo finalmente capire come React gestisce lo stato dei componenti. Nella funzione getInitialState, viene inizializzato quasi fosse un costruttore, dopodiché attraverso il metodo setState possiamo modificare lo stato a nostro piacimento. Ogni cambiamento di stato in qualsiasi componente scatenerà un render totale di tutta l’applicazione in maniera trasparente. Nel nostro caso questo avviene quando salviamo o eliminiamo un todo. Questo è il risultato finale.

React todo-list

React todo-list

Conclusioni

Dopo questo piccolo tutorial sarete in grado di iniziare a creare progetti con React. Qualcuno di voi si starà chiedendo: “ma il routing? la dependency injection? c’era bisogno di tutte quelle callback?” ma dovete tenere presente che React è un tool e non un framework completo come AngularJS. Quindi potete creare il vostro stack mescolando tool differenti. La galassia React si sta popolando di un numero enorme di progetti e best practices che saranno oggetto di analisi in appositi post. Consiglio caldamente a tutti di studiare un po’ di React in quanto potrebbe diventare “the next big thing” dello sviluppo web.

Come al solito i più curiosi possono trovare il sorgente di questa applicazione sul repository GitHub di CNJ. Alla prossima!

Francesco Strazzullo

Faccio il Front-end developer per e-xtrategy dove mi occupo di applicazioni AngularJS e mobile. In passato ho lavorato principalmente con applicazioni con stack Spring+Hibernate+JSF 2.X+Primefaces. Sono tra i collaboratori del progetto Primefaces Extensions: suite di componenti aggiuntivi ufficialmente riconosciuta da Primefaces. Sono anche uno dei fondatori del progetto MaterialPrime: una libreria JSF che segue le direttive del Material Design di Google. 

  • Premetto che non ho mai utilizzato ne Angular e ne React, ma il fatto che abbia un supporto “nativo” per il rendering server side devo ammettere che alimenta la mia voglia di provarlo.

    Quale stack consiglieresti per uno sviluppo con React?

    Immagino che comunque il rendering server side funziona solo con il runtime node.js oppure è possibile l’integrazione con altri linguaggi?

    • Ciao,
      Qualcuno sta provando a utilizzare Java, in particolare Rhino o Nashorn che ti permettono di eseguire codice Javascript in una JVM. Ma sinceramente credo siano degli “hack” e dato che React mi sembra indicato per webapp di medio/grandi dimensioni non ci farei affidamento.

  • Pingback: Test con React - #{francescoStrazzullo}()

  • Pingback: Sviluppare applicazioni con React e Flux - CoseNonJaviste()