Skip to content

Instantly share code, notes, and snippets.

@lopezjurip
Created December 1, 2015 01:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lopezjurip/13cb66c54f7fcfd5cee2 to your computer and use it in GitHub Desktop.
Save lopezjurip/13cb66c54f7fcfd5cee2 to your computer and use it in GitHub Desktop.
Paper Web Avanzado
# React Native
> Nombre: **Patricio López Juri**
> Número alumno: **1263476J**
> Github: **[github.com/mrpatiwi](https://github.com/mrpatiwi)**
## Introducción
### Aplicaciones *cross-platform*
La manera tradicional de desarrollar aplicaciones móvil es escribirlas en el lenguaje específico de la plataforma.
* Android: `Java`, `Scala` o `Kotlin`
* iOS: `Swift` u `Objetive-C`
* Windows Phone: `C#`
Sin embargo esto es costoso cuando se requiere re-escribir código que es común para todas las plataformas y posteriormente mantenerlos todos al día.
Cabe mencionar que está la opción de utilizar lenguajes de bajo nivel como `C++` con el fin de desarrollar una base común. Sin embargo, el lenguaje de por si es complejo y se requiere escribir el código que haga de puente entre las plataformas y la base común. Además, no siempre es posible desarrollar las interfaces gráficas usando estas herramientas.
### React Native
La apuesta de Facebook es React Native, un framework para desarrollar aplicaciones para iOS y Android en un mismo proyecto usando Javascript.
Esto permite compartir código entre las plataformas y beneficiarse del gran ecosistema que hay en Node.js y npm.
#### ¿Cómo funciona?
React Native provee una interfaz donde uno puede trabajar en Javascript sobre JavaScriptCore y renderizar componentes específicos y nativos de la plataforma.
Dicho esto, aún podemos escribir código en el lenguaje nativo de la plataforma y acceder al proyecto en su entorno natural.
Al momento de ejecutar en un dispositivo (ya sea virtual o físico), se inicia un servidor local que se encarga de observar los archivos Javascript y actualizar la vista final en el dispositivo.
Esto es distinto a las alternativas convencionales para desarrollo multiplataforma. Anteriormente se hacía correr la aplicación en HTML, CSS y JS dentro de una *WebView*, cómo si fueran una página web y se proveían algunos de los bindings a elementos de más alto nivel específicos de la plataforma, como el acceso a la cámara o al sistema de notificaciones. Exponentes de esta tecnología son Phonegap, Cordova, Ionic, entre otros.
#### Ventajas de React Native
##### Javascript cómo lenguaje principal
Como ya fue mencionado, podemos escribir un ecosistema completo para una aplicación de gran escala en un mismo lenguaje y reutilizar componentes o librerías.
##### Actualizaciones inmediatas
Es posible durante el desarrollo debugear la aplicación y hacer cambios sin tener que estar reiniciando el programa.
Durante la etapa de *production*, podemos mandar actualizaciones a la aplicación como código Javascript, sin necesidad de depender de las tiendas oficiales de las aplicaciones (Google Play y AppStore) que pueden tardar horas o días en publicar las actualizaciones de la aplicación.
#### Desventajas
Actualmente React Native está bajo arduo desarrollo y puede que ocurran cambios importantes con el paso del tiempo.
Así mismo, no toda la API nativa de cada plataforma es accesible a través de React Native.
En segundo lugar, es un framework relativamente nuevo y aún falta adopción por parte del público, esto trae como consecuencia módulos inmaduros y falta de ejemplos, tutoriales y ayuda en internet.
Se criticado que React Native carece de una documentación completa y fidedigna a las últimas versiones.
También carece de un sistema de control de paquetes, actualmente hay que estar dependiendo de `npm` para los componentes en Javascript, `Cocoapods` para los bindings a iOS y `gradle` para el caso de Android. Se necesita urgentemente un estándar para la integración de módulos transversales.
#### Ejemplos existentes
Podemos ver algunas aplicaciones hechas con React Native en la página oficial del framework:
> https://facebook.github.io/react-native/showcase.html
## Aplicaciones con React Native
### Arquitectura
#### Estructura del directorio
Un proyecto típico tiene la siguiente estructura:
```
Project
├── android
│ ├── app
│ │ └── ...
│ └── ...
├── ios
│ ├── Project.xcodeproj
│ ├── Project
│ │ └── ...
│ └── ProjectTests
│ └── ...
├── index.ios.js
├── index.android.js
├── node_modules
│ └── ...
└── package.json
```
Se puede ver que tenemos las carpetas `android` y `ios`, las cuales contienen el proyecto de la plataforma específica preparado para soportar el desarrollo con React Native.
Los archivos `index.android.js` y `index.ios.js` son los puntos de entrada de la aplicación al momento de ejecutarla.
El directorio `node_modules` y el archivo `package.json` corresponden a los archivos típicos de un proyecto en Node.js.
#### Estructura del entorno
Como ya se mencionó, se inicia un servidor local que actualiza la interfaz que uno ve.
Ya sea para iOS o Android, el servidor es el mismo. Al dispositivo donde corren se le agregan funcionalidades adicionales relacionadas con React Native para poder tener más control y opciones durante el desarrollo.
### Herramientas
El prerrequisito más importante es contar con el sistema operativo Mac OSX.
En primera instancia se necesita de Node.js y su administrador de paquetes (npm). Listo esto, se instala la Command Line Interface (CLI) de React Native por medio de npm.
Se requiere instalar `watchman` de Facebook para poder observar los cambios en el directorio. Esto se puede hacer por medio de [Homebrew](http://brew.sh).
Facebook también sugiere utilizar **Flow**, una herramienta que permite anotaciones y tipado opcional en el código Javascript. Sin embargo esto es opcional.
Si se desea utilizar algún pre-procesador de Javascript tal como **Typescript**, **Coffeescript** o **Babel** uno puede recurrir a herramientas de construcción como:
* Webpack
* Grunt
* Gulp
* etc.
Y *"compilar"* el código fuente a un Javascript que pueda ser procesado por React Native. Actualmente soporta ES2015, también llamado ES6.
### Ejemplo
Crearemos una aplicación básica usando Typescript cómo lenguaje principal, de esta forma podemos aprovechar la sintexis moderna de Javascript y contar con features que no han sido todavía implementadas en el nucleo de Node.js.
Además de contar con los beneficios de un lenguaje tipado. Esto es valioso cuando se trabaja en proyectos grandes, como suele ser el caso de las aplicaciones móviles. A partir de la versión `1.5` de Typescript es soportado trabajar con la sintaxis de Javascript con elementos de marcación embebidos.
> El proyecto completo de ejemplo se encuentra en:
> https://github.com/mrpatiwi/ReactNativeTS
#### Pre-requisitos
Tener al menos la versión 4.x de Node.js. En este caso se usará la última versión hasta el momento (5.1.0).
Instalar React-Native CLI:
```sh
npm install -g react-native-cli
```
Instalar `watchman` para monitorear cambios en los archivos:
```sh
brew install watchman
```
Instalar *TypeScript Definition manager* (`tsd`) para administrar los tipados:
```sh
npm install -g tsd
```
#### Setup
Para iniciar el desarrollo, hacemos el scaffold de la aplicación con:
```sh
react-native init ReactNativeTS
cd ReactNativeTS
```
Luego preparamos el entorno para trabajar con Typescript. Usaremos `gulp` como *build system*.
```sh
# Install development dependencies
npm install --save-dev typescript gulp gulp-typescript
# Init Typescript and tsd
tsd init && tsc --init
# Install React-Native typings
tsd install react-native --save
```
Con esto, en el directorio del proyecto aparecerán dos archivos más de configuración:
* `tsconfig.json`: Configuración de Typescript.
* `tsd.json`: Control de definiciones (tipados).
A modo de hacer el proyecto compatible con Typescript, debemos configurar `tsconfig.json` de la siguiente forma:
```json
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"jsx": "react",
"noImplicitAny": true,
"experimentalDecorators": true,
"preserveConstEnums": true,
"outDir": "built",
"rootDir": "src",
"sourceMap": true
},
"filesGlob": [
"typings/**/*.d.ts",
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
```
> En palabras simples, esto dice: compilar con compatibilidad con React y ECMAScript 6 los contenidos de `src` a la carpeta `built`.
Una configuración posible para `gulp` es la siguiente:
```javascript
// gulpfile.js
var gulp = require('gulp');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');
gulp.task('build', function() {
var tsResult = tsProject.src().pipe(ts(tsProject));
return tsResult.js.pipe(gulp.dest('built'));
});
gulp.task('watch', ['build'], function() {
gulp.watch('src/**/*.ts', ['build']);
gulp.watch('src/**/*.tsx', ['build']);
});
gulp.task('default', ['build']);
```
> `gulp build`: Compila el proyecto
> `gulp watch`: Ante cualquier cambio, ejecutar `gulp build`.
#### Hello world
> Los archivos para cada plataforma son del estilo: `filename.platform.js` o `filename.platform.jsx`.
> Por ejemplos los archivos de entrada ubicados en la raíz son `index.ios.js` y `index.android.js`.
> Cabe mencionar que si queremos utilizar el mismo archivo para ambas plataformas, basta con nombrarlo cómo `filename.js` o `filename.jsx` y funcionará automáticamente.
Editamos los archivos `index.ios.js` y `index.android.js` para que carguen la app desde la carpeta `built`:
```javascript
'use strict'
import { AppRegistry } from 'react-native'
import App from './built'
AppRegistry.registerComponent('ReactNativeTS', () => App)
```
Finalmente, en `src/index.ios.tsx` y en `src/index.android.tsx` creamos el *home* de la aplicación:
```tsx
/// <reference path="../typings/tsd.d.ts"/>
import React from "react-native";
const { StyleSheet, Text, View } = React;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF",
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10,
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5,
},
});
export default class App extends React.Component<any, any> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native
</Text>
<Text style={styles.instructions}>
To get started, edit src contents
</Text>
</View>
);
}
}
```
#### Aplicación de Ejemplo
Se puede hacer fácilmente un timer. En este caso es necesario hacer uso de las `properties` y el `state` de un componente React.
En Typescript podemos asignar inmediatamente qué serán esos objetos al crear `interfaces`.
```tsx
interface State {
ticks: number;
}
interface Props {
interval: number;
}
export default class App extends React.Component<Props, State> {
static defaultProps = { interval: 10 };
constructor(props?: any) {
super(props);
this.state = { ticks: 0 };
}
componentDidMount() {
setInterval(() => {
this.setState({ ticks: ++this.state.ticks });
}, this.props.interval);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Ticks: {this.state.ticks + "\n\n"}
At {this.props.interval} ms per tick
</Text>
</View>
);
}
}
```
Es importante notar que el timer se debe iniciar en `componentDidMount`, esto es legado de cómo funcionan las aplicaciones nativas. Puesto que cuando se construyen no nos aseguraran que estén disponibles en la jerarquía de vistas.
![Tick preview](https://cloud.githubusercontent.com/assets/7570744/11457671/c7316bcc-968d-11e5-9133-03f1e248cbbe.png)
## Discusión
### Proceso de desarrollo
Javascript es un lenguaje super expresivo y simple. Se pudo crear un timer sin estar dependiendo de threads, dispatches y/o eventos.
El sistema de estilo está fuertemente inspirado en CSS que suele usarse en web. Esto hace mucho más simple el desarrollo de vistas. En la metodología tradicional, cada plataforma en específico se comportan de manera distintas y se requiere fuerte manejo en constantes, interfaces de desarrollo como XCode o Android Studio y manejo de grandes frameworks.
### Extensibilidad
El entorno de React está pensado para integrársele muchas librerías. Esto puede ser bueno para la extensibilidad de componentes de la plataforma. Sin embargo, carece de componentes que se esperaría que estuvieran integrados en el núcleo de React Native.
Como consecuencia, no se puede tener soporte oficial de Facebook para algunos componentes tan primitivos como los botones. Estos hay que instalarlos como dependencias no oficiales, así como muchos otros.
### Performance
Facebook asegura que React Native intenta ser lo más óptimo posible. Sin embargo, dada la naturaleza single-thread de Javascript, puede que ocurran inconvenientes al realizar animaciones que no sigan la metodología sugerida por ellos.
También pueden ocurrir problemas de bloqueo cuando se realizan operaciones largas y exigentes en el thread principal.
> Performance Guide:
> https://facebook.github.io/react-native/docs/performance.html
## Conclusión
Puede que Facebook haya terminado definitivamente el debate entre aplicaciones nativas e híbridas. Porque finalmente existe una manera de desarrollar aplicaciones móviles multi-plataformas y eficientes.
Si bien aún existe el approach de Xamarin cuyo desarrollo se hace en C# y lleva años de madurez, es una solución pagada y nunca tendrá la gran comunidad que gira entorno a Node.js y Javascript.
Falta esperar que React Native llegue a etapas más maduras y que algún día de soporte para Windows Phone.
---
> Written with [StackEdit](https://stackedit.io/).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment