React Native
Nei miei ultimi post mi sono occupato di React: framework frontend creato da Facebook che è ormai l’ultima moda in fatto di sviluppo web. React-native è un progetto parallelo il cui scopo è quello di creare applicazioni native iOS e Android. Il risultato non sarà infatti un’applicazione ibrida in stile Apache Cordova ma una vera e propria applicazione nativa, scritta però nello stile React. Il framework ad oggi include una serie di componenti e delle API che ci permettono di accedere alle features del dispositivo quali vibrazione, fotocamera, etc.
Setup
Alla fine di questo post saremo in grado di scrivere la solita todo-list in React Native. Come prima cosa dobbiamo installare React-native tramite il comando:
npm install -g react-native-cli
Dopodichè possiamo inizializzare il nostro progetto, tramite il comando:
react-native init TodoList
La situazione della cartella TodoList una volta terminata la procedura sarà la seguente:
Filesystem di un progetto “blank”
la cosa che salta più all’occhio è la presenza di due files: index.ios.js e index.android.js. Il punto di ingresso dell’applicazione sarà differente a seconda della piattaforma scelta. Questa feature può sembrare poco intuitiva per un tool che si professa multipiattaforma, ma in realtà ha una sua logica. Il motto di react-native è “learn once, run anywhere” a differenza del solito “write once, run anywhere”. Lo scopo di react-native è quello di poter fornire la maggiore aderenza possibile al look and feel della piattaforma scelta anche a costo di avere codice che (almeno in parte) diverge.
Let’s code!
Passiamo ora al codice dell’applicazione. Implementeremo una todo-list il cui codice sarà identico in entrambe le piattaforme supportate. Per questo esempio la parte di business logic è presa integralmente dal mio ultimo post su . Quindi in questo caso ci concentreremo solo sulla parte View del progetto. Iniziamo con il codice della root dell’applicazione:
var React = require('react-native'); var Form = require('./Form'); var List = require('./List'); var { StyleSheet, Text, View } = React; var styles = StyleSheet.create({ title: { fontSize: 20, textAlign: 'center', margin: 10, } }); module.exports = class extends React.Component{ render() { return (); } } React Native Todo-List
La struttura di un’applicazione React-native è perfettamente identica a quella di un’applicazione React classica. Unica differenza sta nell’utilizzo di tag forniti dal framework (come View
e Text
) al posto dei classici tag HTML. I tag Form
e List
rappresentano invece dei componenti custom di cui analizziamo subito il codice. Iniziamo dal componente Form
:
var React = require('react-native'); var Actions = require('../Actions'); var { StyleSheet, TextInput, View, TouchableHighlight, Text } = React; var styles = StyleSheet.create({ row: { flexDirection: 'row', margin: 30 }, input: { flex: 9, borderWidth: 1, borderColor: 'black' }, button: { flex: 3, padding: 5, borderWidth: 1, marginLeft: 10, borderColor: 'black', borderRadius: 5 } }); module.exports = class extends React.Component { constructor(props) { super(props); this.state = { todoText: "" }; this.onSavePress = this._onSavePress.bind(this); this.onChangeInput = this._onChangeInput.bind(this); } _onSavePress() { if (this.state.todoText) { Actions.add(this.state.todoText); this.setState({ todoText: "" }); } } _onChangeInput(event) { this.setState({ todoText: event.nativeEvent.text }); } render() { return (); } } Save
Come vediamo questo componente non presenta caratteristiche particolari, rispetto ad una canonica applicazione React. Passiamo ora all’elemento List
.
var React = require('react-native'); var Store = require('../Store'); var Actions = require('../Actions'); var { StyleSheet, View, ListView, Text, TouchableHighlight } = React; var styles = StyleSheet.create({ row: { flex: 1, flexDirection: 'row', borderWidth:1, marginLeft:10, borderColor:'black', borderRadius:2, marginTop:5, padding: 5 }, todoText:{ flex:9 }, deleteButton:{ flex:3, borderWidth:1, borderColor:'black', borderRadius:5, backgroundColor:'red' }, listView: { paddingLeft: 30, paddingRight: 30 } }); module.exports = class extends React.Component{ constructor(props) { super(props); this.state = { dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) }; this.listener = this._listener.bind(this); this.renderRow = this._renderRow.bind(this); } _listener(){ this.setState({ dataSource: this.state.dataSource.cloneWithRows(Store.get()) }); } _onDeletePress(rowId){ Actions.delete(parseInt(rowId,10)); } componentDidMount() { Store.addChangeListener(this.listener); } componentWillUnmount() { Store.removeChangeListener(this.listener); } _renderRow(todo,sectionID,rowId) { return (); } render() { return ( {todo} Delete ); } }
all’interno di List
possiamo notare la presenza della ListView
il repeater base di React-native. Questo componente ha bisogno di due attributi fondamentali:
-
dataSource: la sorgente dati del repeater, da notare che in fase di inizializzazione gli viene passata la funzione
rowHasChanged
che indica quando una riga può essere considerata modificata (quando cioè rilanciare il render dellaListView
) - renderRow: metodo che si occupa di eseguire il render della singola riga
Avvio e debug
Per avviare l’applicazione dobbiamo utilizzare XCode nel caso di piattaforma iOS oppure invocare il comando react-native run-android
per quanto riguarda Android. Il risultato del codice visto in precedenza è il seguente:
React-native todo-list
Premendo ⌘-D per quando l’applicazione gira all’interno del simulatore iOS, oppure premendo il pulsante “menù” su un emulatore Android verrà fuori il menù debug di react-native, che comprende moltissime funzioni utili come il live reload, l’inspect degli elementi e il debug su chrome o safari.
Debug menu
Inspect element
Conclusioni
React-native è un progetto molto giovane, il supporto ad Android è ufficiale da pochissimo tempo. Ma ha già parecchie frecce al suo arco. La cosa più impressionante è l’enorme efficacia del suo debug menù: su android si hanno tempi di build ridicoli e un live reload funzionante. Altra caratteristica interessante è la possibilità (che abbiamo sfruttato nel nostro esempio) di recuperare completamente la business logic di una pre-esistente applicazione React web. Non credo che ad oggi sia un prodotto valido per creare app da mandare in produzione, ma è sicuramente il framework da tenere d’occhio nei prossimi mesi per chi si interessa di sviluppo mobile multipiattaforma.
Il sorgente dell’applicazione è disponibile, come sempre, al repository GitHub di cosenonjaviste.