Más fácil reaccionar Desarrollo nativo con Expo

Expo es una colección de herramientas que facilitan la codificación de las aplicaciones nativas React. En este tutorial, te mostraré cómo puedes crear rápidamente las aplicaciones React Native usando Expo.

Con Expo, los desarrolladores pueden crear aplicaciones React Native sin las frustraciones que conlleva la instalación y configuración de dependencias de software como Android Studio, Xcode o todas las demás herramientas necesarias para desarrollar y ejecutar una aplicación React Native.. 

En este tutorial, te mostraré cómo crear un juego de memoria simple utilizando Expo. En el camino también aprenderás lo siguiente:

  • Cómo utilizar las herramientas proporcionadas por Expo. Esto incluye el CLI, el SDK y la aplicación cliente Expo..
  • Cómo crear una aplicación React Native usando Expo.

Que es la expo?

Expo es un marco para el rápido desarrollo de aplicaciones React Native. Es como Laravel o Symphony para desarrolladores de PHP, o Ruby on Rails para desarrolladores de Ruby. Expo proporciona una capa sobre las API nativas de React para que sean más fáciles de usar y administrar. También proporciona herramientas que facilitan el arranque y la prueba de las aplicaciones nativas React. Por último, proporciona componentes y servicios de UI que normalmente solo están disponibles cuando instala un componente React Native de terceros. Todos ellos están disponibles a través del SDK de Expo.

Limitaciones de la expo

Antes de continuar, es importante conocer algunas de las limitaciones de Expo: 

  1. Aplicaciones de expo no hacer soporte de ejecución de código de fondo. Esto significa que no puede, por ejemplo, ejecutar un código que escuche los cambios de ubicación cuando se cierra la aplicación.
  2. Las aplicaciones de Expos están limitadas a las API nativas que admite Expo SDK. Esto significa que si su aplicación tiene un caso de uso muy específico, como comunicarse con un periférico Bluetooth, la única opción para implementar dicha funcionalidad es con React Native, o escribiendo código nativo usando una biblioteca llamada ExpoKit.
  3. Expo te bloquea dentro su conjunto de herramientas. Esto significa que no puede simplemente instalar y utilizar la mayoría de las grandes herramientas disponibles para el desarrollo React Native, como herramientas de línea de comandos, andamios y marcos de UI. Pero lo bueno es que el SDK de Expo es compatible con las aplicaciones nativas React simples, por lo que no tendrá ningún problema al expulsar su aplicación de Expo..
  4. Los binarios independientes de las aplicaciones de Expo solo se pueden construir en línea. Expo proporciona una herramienta de línea de comandos llamada Exp. Esto permite a los desarrolladores iniciar el proceso de compilación en los servidores Expo. Una vez hecho esto, se proporcionará una URL para descargar el .apk o .ipa expediente. 

Incluso con estas limitaciones, es importante tener en cuenta que Expo es un marco completamente funcional con mucho soporte para las API de Android o iOS más utilizadas. Esto significa que lo tiene cubierto para la mayoría de las funcionalidades que las aplicaciones comúnmente necesitan. Por lo tanto, a menudo no es necesario mirar fuera de Expo para implementar la funcionalidad nativa.

Descripción de la aplicación

La aplicación que vamos a crear es un juego de memoria. Es posible que esté familiarizado con este tipo de juego: el usuario tiene que encontrar pares coincidentes entregando las cartas de dos en dos. Así es como se ve la pantalla predeterminada:

Y así es como se ve una vez que se han abierto todas las parejas:

Una vez que hayan resuelto el juego, el usuario puede tocar en el Reiniciar botón para restablecer los elementos a su estado inicial. Esto les permite comenzar el juego de nuevo..

Instalacion de expo

A diferencia de plain React Native, donde tiene que instalar y configurar Android Studio o Xcode y otras dependencias, con Expo solo hay unos pocos pasos a seguir para comenzar a desarrollar aplicaciones:

  1. Descargar e instale Node.js. Expo depende de la plataforma Node.js para sus herramientas de línea de comandos y la gestión de dependencias..
  2. Instale el Expo Client en su iOS o Androide dispositivo. Esto se usa para obtener una vista previa de la aplicación mientras la estás desarrollando.
  3. Instalar la herramienta de línea de comandos. Esto le permite generar un nuevo proyecto de Expo, iniciar un proceso de compilación y más. Ejecute el siguiente comando para instalarlo: 
npm install exp --global

Generando una nueva aplicación de Expo

Una vez que haya instalado todas las dependencias, ahora puede generar una nueva aplicación Expo:

exp init MemoryGame

Una vez hecho esto, se creará una nueva carpeta llamada Juego de memoria. Navegue dentro de él y comience a ejecutar el servidor de desarrollo:

cd MemoryGame exp start

Alternativamente, también puede utilizar la Expo XDE. Esto le permite crear y ejecutar aplicaciones de Expo a través de una GUI. Puedes descargar el instalador desde el repositorio de Expo GitHub. Actualmente, solo es compatible con Windows y Mac. Así que si estás en Ubuntu o Linux es mejor seguir con la línea de comandos por ahora.

Una vez que el servidor de desarrollo se está ejecutando, ahora debería poder ver algo como esto:

Ese es el código QR que apunta a la vista previa en vivo del proyecto. Abra la aplicación cliente Expo en su teléfono y escanee el código con el escáner QR. En este punto, ahora debería poder ver la pantalla predeterminada. Cada vez que golpeas Control-S en cualquiera de los archivos del proyecto, la vista previa debería volver a cargarse automáticamente para reflejar los cambios.

Puede encontrar el código fuente completo del proyecto en su repositorio de GitHub. O si desea probar la aplicación, puede ver la demostración. Simplemente seleccione Código QR y escanéelo en su teléfono usando la aplicación de cliente Expo.

Codificando la aplicación

Ahora estamos listos para codificar la aplicación. Comencemos con algunos componentes de la interfaz de usuario antes de regresar e implementar el componente principal.

Componente de encabezado

El encabezado se utiliza para mostrar el título de la aplicación. Crear un componentes carpeta. Dentro de ella, crea un Header.js archivo y añadir lo siguiente:

importar reaccionar desde 'reaccionar'; importar StyleSheet, Text, View desde 'react-native'; exportar la clase predeterminada Encabezado extiende React.Component render () return (  Juego de memoria  );  const styles = StyleSheet.create (header: flex: 1, flexDirection: 'column', alignSelf: 'stretch', paddingTop: 20, paddingBottom: 5, backgroundColor: '# f3f3f3', header_text: fontWeight: 'bold', fontSize: 17, textAlign: 'center');

Este es solo un componente básico de React Native, con algunos estilos para coincidir con la interfaz de usuario de nuestra aplicación. 

Componente de puntuación

El siguiente es el componente para mostrar la puntuación (componentes / Score.js):

importar reaccionar desde 'reaccionar'; importar StyleSheet, Text, View desde 'react-native'; exportar la clase predeterminada Puntaje extiende React.Component render () return (  this.props.score  );  estilos const = StyleSheet.create (score_container: flex: 1, alignItems: 'center', padding: 10, score: fontSize: 40, fontWeight: 'bold');

De nuevo, solo un componente de visualización simple con una vista de texto y algunos estilos básicos.

Componente de la tarjeta

El componente de la tarjeta (componentes / Card.js) mostrará las tarjetas. Estas tarjetas utilizan iconos del conjunto de iconos de vectores de Expo. Esta es una de las características que salen de la caja cuando se usa Expo: incluye iconos de conjuntos de iconos como FontAwesome, Entypo e Ionicons. 

En el código a continuación, puedes ver que solo estamos usando FontAwesome. Tiene el icono que queremos para mostrar el estado predeterminado de la tarjeta: un signo de interrogación. Como verá más adelante en el componente principal de la aplicación, también usaremos íconos de Entypo e Ionicons. La referencia a esas fuentes de iconos se pasará a este componente, por lo que no es necesario especificarlas aquí:

importar reaccionar desde 'reaccionar'; importar StyleSheet, Text, View, TouchableHighlight desde 'react-native'; importe FontAwesome desde '@ expo / vector-icons'; // usa FontAwesome de los iconos de vectores de la expo

Dentro de hacer() Método, solo usamos la fuente y el icono pasados ​​como accesorios si la tarjeta está abierta. De forma predeterminada, solo mostrará el icono de signo de interrogación de FontAwesome. Pero si la tarjeta está abierta, utilizará la fuente del icono, el icono y el color que se pasaron como accesorios. 

Cada una de las cartas puede ser girada. Cuando se toca, el tarjeta de clic () Se ejecutará la función, que también se pasa a través de los accesorios. Más adelante verás lo que hace la función, pero por ahora, solo debes saber que se actualiza el estado para revelar el ícono en la tarjeta: 

la tarjeta predeterminada de la clase de exportación extiende React.Component render () deja CardSource = FontAwesome; // establece FontAwesome como la fuente de iconos predeterminada let icon_name = 'question-circle'; Deje que icon_color = '# 393939'; if (this.props.is_open) CardSource = this.props.src; icon_name = this.props.name; icon_color = this.props.color;  regreso (      ); 

No olvides añadir los estilos:

const styles = StyleSheet.create (card: flex: 1, alignItems: 'center', card_text: fontSize: 50, fontWeight: 'bold');

Ayudantes

También usaremos una función de ayuda llamada barajar(). Esto nos permite ordenar el conjunto de cartas en orden aleatorio para que su orden sea diferente cada vez que se reinicie el juego:

Array.prototype.shuffle = function () var i = this.length, j, temp; si (i == 0) devuelve esto; while (- i) j = Math.floor (Math.random () * (i + 1)); temp = este [i]; este [i] = este [j]; este [j] = temp;  devuelve esto; 

Componente principal

El componente principal (App.js) contiene la lógica principal de la aplicación y reúne todo. Comience por incluir los paquetes React y Expo que usaremos. Esta vez estamos usando todas las fuentes de iconos de los iconos vectoriales de Expo:

importar reaccionar desde 'reaccionar'; importar StyleSheet, View, Button desde 'react-native'; importe Ionicons, FontAwesome, Entypo desde '@ expo / vector-icons';

A continuación, incluya los componentes y el ayudante que creamos anteriormente:

importar encabezado desde './components/Header'; Importar puntaje desde './components/Score'; importar tarjeta desde './components/Card'; importar ayudantes desde './helpers';

Dentro del constructor, primero creamos la matriz que representa las tarjetas únicas. src es la fuente del icono, nombre es el nombre del icono (puede encontrar los nombres en GitHub si desea usar otros iconos), y color Es, naturalmente, el color del icono:

la clase predeterminada de exportación App extiende React.Component constructor (props) super (props); // vincular las funciones a la clase this.renderCards = this.renderCards.bind (this); this.resetCards = this.resetCards.bind (this); // las fuentes de iconos permiten a sources = 'fontawesome': FontAwesome, 'entypo': Entypo, 'ionicons': Ionicons; // los íconos únicos que se usarán let cards = [src: 'fontawesome', name: 'heart', color: 'red', src: 'entypo', name: 'feather', color: '# 7d4b12 ', src:' entypo ', nombre:' flashlight ', color:' # f7911f ', src:' entypo ', nombre:' flower ', color:' # 37b24d ', src:' entypo ', nombre:' luna ', color:' # ffd43b ', src:' entypo ', nombre:' youtube ', color:' # FF0000 ', src:' entypo ', nombre:' shop ', color: '# 5f5f5f', src: 'fontawesome', nombre: 'github', color: '# 24292e', src: 'fontawesome', nombre: 'skype', color: '# 1686D9', src: 'fontawesome', nombre: 'enviar', color: '# 1c7cd6', src: 'ionicons', nombre: 'ios-magnet', color: '# d61c1c', src: 'ionicons' , nombre: 'logo-facebook', color: '# 3C5B9B']; // siguiente: agregue el código creando el clon y configurando las tarjetas en el estado

Tenga en cuenta que en lugar de especificar directamente la src como FontAwesome, Entypo o Ionicones Para cada uno de los objetos, estamos usando los nombres de propiedades utilizados en el fuentes objeto. Esto se debe a que necesitaremos crear una copia de la matriz de tarjetas para que cada tarjeta tenga un par. Creando una copia usando métodos de matriz tales como rebanada() creará una copia de la matriz, pero el problema es que una vez que los objetos individuales se modifican en la copia o en el original, también se modifican ambas matrices. 

Esto nos lleva a la solución a continuación, que es crear un objeto completamente nuevo al convertir el tarjetas matriz en una cadena y luego analizarla para convertirla de nuevo en una matriz. Esta es la razón por la que estamos usando cadenas, ya que las funciones no se pueden convertir en cadenas. Luego, combinamos los dos para crear la matriz, que contiene todas las tarjetas que necesitamos:

let clone = JSON.parse (JSON.stringify (cards)); // crea una matriz completamente nueva a partir de la matriz de tarjetas this.cards = cards.concat (clon); // combina el original y el clon

A continuación, vaya a través de esa matriz y genere una ID única para cada uno, establezca la fuente del icono y luego establezca un estado cerrado de forma predeterminada:

// agregue el ID, la fuente y establezca el estado predeterminado para cada tarjeta this.cards.map ((obj) => let id = Math.random (). toString (36) .substring (7); obj.id = id ; obj.src = fuentes [obj.src]; obj.is_open = false;);

Ordena las tarjetas al azar y establece el estado predeterminado:

this.cards = this.cards.shuffle (); // ordenar las tarjetas al azar // establecer el estado predeterminado this.state = current_selection: [], // esta matriz contendrá una matriz de objetos de tarjetas que el usuario seleccionó actualmente. Esto solo contendrá dos objetos a la vez. selected_pairs: [], // los nombres de los iconos. Esta matriz se utiliza para excluirlos de la puntuación de selección adicional: 0, // tarjetas de puntuación de usuario predeterminadas: this.cards // las tarjetas barajadas

los hacer() El método representa el encabezado, las cartas, la puntuación y el botón para restablecer el juego actual. Esta usando el renderRows () Función para renderizar las filas de cartas individuales. La pantalla tendrá seis filas que contienen cuatro cartas cada una:

render () return (  
this.renderRows.call (this)

Aquí está el código para el renderRows () función. Esto usa el getRowContents () Función, que es responsable de crear una matriz de matrices con cuatro elementos cada una. Esto nos permite renderizar cada fila, y luego usar otra función para renderizar tarjetas para cada iteración de la mapa() función:

renderRows () let contents = this.getRowContents (this.state.cards); return contents.map ((cards, index) => return (  this.renderCards (tarjetas)  ); ); 

Aquí esta la getRowContents () función:

getRowContents (tarjetas) let contents_r = []; dejar contenidos = []; vamos a contar = 0; cards.forEach ((item) => count + = 1; contents.push (item); if (count == 4) contents_r.push (contents) count = 0; contents = [];); devolver contents_r; 

Siguiente es el renderCards () función. Esto acepta la matriz de objetos de la tarjeta y los procesa a través del Tarjeta componente. Todo lo que tenemos que hacer aquí es pasar las propiedades individuales de cada objeto de tarjeta como accesorios. Esto se usa para representar el ícono correcto, como se ha visto en el código para el Tarjeta componente. los tarjeta de clic () La función también se pasa como prop. La identificación de la tarjeta se pasa a esa función para que la tarjeta única pueda ser identificada y actualizada:

renderCards (cards) return cards.map ((card, index) => return (  ); ); 

Dentro de tarjeta de clic () Para ello, obtenemos los detalles de la tarjeta seleccionada y verificamos si debe procesarse más:

clickCard (id) let selected_pairs = this.state.selected_pairs; let current_selection = this.state.current_selection; dejar puntuación = this.state.score; // obtener el índice de la tarjeta actualmente seleccionada let index = this.state.cards.findIndex ((card) => return card.id == id;); deja cards = this.state.cards; // la tarjeta no debería estar abierta y no está en el conjunto de tarjetas cuyos pares ya están seleccionados si (cards [index] .is_open == false && selected_pairs.indexOf (cards [index] .name) === 1) // siguiente: agregar código para procesar la tarjeta seleccionada

Ahora completemos el código para manejar una tarjeta seleccionada. 

Primero, abrimos la tarjeta y la agregamos a la matriz de tarjetas actualmente seleccionadas:

tarjetas [índice] .is_open = verdadero; current_selection.push (index: index, name: cards [index] .name); // siguiente: agregue código para determinar si el usuario ha seleccionado el par correcto o no

Una vez que hay dos elementos en el conjunto de tarjetas actualmente seleccionadas, verificamos si los nombres de los íconos son iguales. Si lo son, significa que el usuario ha seleccionado el par correcto. Si no son lo mismo entonces es un par incorrecto. En ese caso, cerramos la primera tarjeta que se seleccionó y luego agregamos un poco de retraso antes de cerrar la segunda tarjeta. (De esta manera el usuario puede ver el ícono de la tarjeta antes de volver al estado cerrado).

if (current_selection.length == 2) if (current_selection [0] .name == current_selection [1] .name) score + = 1; // incrementa la puntuación selected_pairs.push (cards [index] .name);  else cards [current_selection [0] .index] .is_open = false; // cierra la primera // demora en cerrar la tarjeta actualmente seleccionada en medio segundo. setTimeout (() => cards [index] .is_open = false; this.setState (cards: cards);, 500);  current_selection = [];  // siguiente: agregar código para actualizar el estado

Lo último que debemos hacer en el controlador de eventos de clic es actualizar el estado para reflejar los cambios en la interfaz de usuario:

this.setState (score: score, cards: cards, current_selection: current_selection);

Una función relacionada es el controlador de eventos de reinicio. Cuando el Reiniciar botón pulsado, simplemente restauramos el estado predeterminado cerrando todas las tarjetas y barajando.

resetCards () // cierra todas las tarjetas let cards = this.cards.map ((obj) => obj.is_open = false; return obj;); cards = cards.shuffle (); // volver a barajar las tarjetas // actualizar al estado predeterminado this.setState (current_selection: [], selected_pairs: [], cards: cards, score: 0); 

Finalmente, agregaremos algunos estilos básicos para hacer que nuestra aplicación se vea bien..

const styles = StyleSheet.create (container: flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', row: flex: 1, flexDirection: 'row', body: flex: 18, justifyContent: 'space-between', padding: 10, marginTop: 20);

Prueba la aplicación

Debido a que su servidor de desarrollo Expo ha estado funcionando todo este tiempo, cada cambio debe ser enviado a su dispositivo móvil con recarga en vivo. Prueba la aplicación y asegúrate de que funcione como debe.

Conclusión

¡Eso es! En este tutorial, aprendió a usar Expo XDE para conectar rápidamente una aplicación React Native. Expo es una muy buena manera de comenzar a desarrollar aplicaciones React Native porque elimina la necesidad de instalar una gran cantidad de software que a menudo es motivo de frustración, especialmente para los principiantes. También proporciona herramientas que facilitan la vista previa de la aplicación mientras se desarrolla. Asegúrese de consultar los recursos mencionados en el sitio web de la Expo si desea obtener más información.

Y mientras tanto, eche un vistazo a algunas de nuestras otras publicaciones sobre el desarrollo de aplicaciones nativas React!