Desarrollo Más Fácil React Native con Expo
Spanish (Español) translation by James (you can also view the original English article)
Expo es una colección de herramientas que facilitan aplicaciones nativas reaccionan código. En este tutorial, voy a mostrarle cómo usted puede crear rápidamente aplicaciones nativas reaccionan con Expo.
Con la Expo, los desarrolladores pueden crear aplicaciones nativas reaccionan sin todas las frustraciones que vienen con la instalación y configuración de las dependencias de software como Android Studio, Xcode o todas las herramientas necesarias para desarrollar y ejecutar una aplicación nativa de reaccionar.
En este tutorial voy a mostrar cómo crear un juego de memoria simple con Expo. En el camino también aprenderás lo siguiente:
- Cómo utilizar las herramientas proporcionadas por la Expo. Esto incluye el CLI, SDK y la aplicación de cliente de la Expo.
- Cómo crear una aplicación nativa reaccionan con Expo.
¿Qué es Expo?
Expo es un framework para desarrollar rápidamente aplicaciones React Native. Es como Laravel o sinfonía de los desarrolladores PHP o Ruby on Rails para los desarrolladores de Ruby. Expo proporciona una capa encima de las API React Native para hacerlos más fáciles de utilizar y administrar. También proporciona herramientas que facilitan el arranque y probar aplicaciones React Native. Por último, proporciona servicios que normalmente sólo están disponibles cuando se instala un componente nativo reaccione de terceros y componentes de interfaz de usuario. Todos los se hacen disponibles a través del SDK de la Expo.
Limitaciones de Expo
Antes de seguir adelante, es importante ser consciente de algunas de las limitaciones de Expo:
- Expo aplicaciones no admiten la ejecución de código de fondo. Esto significa que usted no puede, por ejemplo, ejecute código que escucha los cambios de situación cuando se cierra la aplicación.
- Aplicaciones de Expos se limitan a las API nativas que es compatible con el SDK de Expo. Esto significa que si tu aplicación tiene un caso de uso muy específico como comunicarse con un periférico, la única opción para implementar dicha funcionalidad es normal reaccionar nativo o escribiendo código nativo usando una librería llamada ExpoKit Bluetooth.
- Expo quede su toolset. Esto significa que simplemente no se puede instalar y utilizar la mayoría de las grandes herramientas para el desarrollo React Native como herramientas de línea de comandos, andamios y estructuras de interfaz de usuario. Pero lo bueno es que el SDK de la Expo es compatible con aplicaciones React Native llano, para que no tengas ningún problema al expulsar su aplicación de Expo.
- Independiente binarios de aplicaciones Expo sólo pueden construirse en línea. Expo ofrece una herramienta de línea de comandos llamada Exp. Esto permite a los desarrolladores a iniciar el proceso de construcción en los servidores de la Expo. Una vez hecho, se proporcionará un enlace para descargar el archivo .apk o .ipa.
Incluso con estas limitaciones, es importante tener en cuenta que la Expo es un marco totalmente funcional con un montón de apoyo comúnmente usado APIs de iOS o Android. Esto significa que tiene cobertura para la mayoría de las funcionalidades que las aplicaciones normalmente necesitan. Así que no hay a menudo parecen fuera de Expo para implementar la funcionalidad nativa.
Resumen de la Aplicación
La aplicación que vamos a crear es un juego de memoria. Usted puede familiarizarse con este tipo de juego, el usuario tiene que buscar parejas de entregar tarjetas de dos a la vez. Esto es lo que parece la pantalla por defecto:



Y aquí es cómo se ve como una vez todos los pares se han abierto:



Una vez que han solucionado el juego, el usuario puede Pulse el botón reset para restablecer los elementos a su estado inicial. Esto les permite empezar el juego otra vez.
Instalación de Expo
A diferencia de simple reaccionar nativo donde usted tiene que instalar y configurar Android Studio o Xcode y otras dependencias, con Expo hay sólo unos pocos pasos a seguir para empezar a desarrollar aplicaciones:
- Descargar e instalar Node.js. Expo depende de la plataforma de Node.js para sus herramientas de línea de comandos y gestión de la dependencia.
- Instalar al Cliente de Expo en su Dispositivo Android o iOS. Se utiliza para obtener una vista previa de la aplicación mientras que usted está desarrollando.
- Instale la herramienta de línea de comandos. Esto le permite generar un nuevo proyecto de la Expo, iniciar un proceso de construcción y mucho más. Ejecute el siguiente comando para instalarlo:
1 |
npm install exp --global |
Generar una Nueva Aplicación de Expo
Una vez que has instalado todas las dependencias, ahora puede generar una nueva aplicación de Expo:
1 |
exp init MemoryGame |
Una vez hecho esto, creará una nueva carpeta llamada MemoryGame. Navegar dentro de él y empezar a correr el servidor de desarrollo:
1 |
cd MemoryGame
|
2 |
exp start |
Alternativamente, también puede utilizar el XDE Expo. Esto le permite crear y ejecutar aplicaciones de la Expo a través de una GUI. Puede descargar al instalador desde el repositorio de GitHub Expo. Actualmente, sólo 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 se está ejecutando el servidor de desarrollo, ahora debe poder ver algo como esto:



Es el código QR que señala a la previsualización del proyecto. Abra la aplicación de cliente de la Expo en su teléfono y escanear el código usando el lector de QR. En este punto, ahora debe poder ver la pantalla por defecto. Cada vez que usted golpea Control-S en cualquiera de los archivos del proyecto, la vista previa debe cargar automáticamente para reflejar los cambios.
Usted puede encontrar el código fuente completo del proyecto en su repositorio GitHub. O si quieres probar la aplicación, puede informarse sobre la demostración. Sólo seleccione código QR y escanear en su teléfono usando la aplicación de cliente de la Expo.
Codificación de la Aplicación
Ahora estamos listos para la aplicación del código. Vamos a empezar con algunos componentes de interfaz de usuario antes de volver y de implementación del componente principal.
Componente de Encabezado
El encabezado se utiliza para mostrar el título de la aplicación creando una carpeta de componentes. En su interior, crea un archivo Header.js y añadir lo siguiente:
1 |
import React from 'react'; |
2 |
import { StyleSheet, Text, View } from 'react-native'; |
3 |
|
4 |
export default class Header extends React.Component { |
5 |
|
6 |
render() { |
7 |
return ( |
8 |
<View style={styles.header}> |
9 |
<Text style={styles.header_text}>MemoryGame</Text> |
10 |
</View> |
11 |
);
|
12 |
}
|
13 |
|
14 |
}
|
15 |
|
16 |
const styles = StyleSheet.create({ |
17 |
header: { |
18 |
flex: 1, |
19 |
flexDirection: 'column', |
20 |
alignSelf: 'stretch', |
21 |
paddingTop: 20, |
22 |
paddingBottom: 5, |
23 |
backgroundColor: '#f3f3f3' |
24 |
},
|
25 |
header_text: { |
26 |
fontWeight: 'bold', |
27 |
fontSize: 17, |
28 |
textAlign: 'center' |
29 |
}
|
30 |
});
|
Esto es sólo un componente React Native básico, con un estilo para que coincida con la interfaz de usuario de nuestra aplicación.
Componente Puntaje
El siguiente es el componente para la visualización de la puntuación (components/Score.js):
1 |
import React from 'react'; |
2 |
import { StyleSheet, Text, View } from 'react-native'; |
3 |
|
4 |
export default class Score extends React.Component { |
5 |
|
6 |
render() { |
7 |
return ( |
8 |
<View style={styles.score_container}> |
9 |
<Text style={styles.score}>{this.props.score}</Text> |
10 |
</View> |
11 |
);
|
12 |
}
|
13 |
|
14 |
}
|
15 |
|
16 |
const styles = StyleSheet.create({ |
17 |
score_container: { |
18 |
flex: 1, |
19 |
alignItems: 'center', |
20 |
padding: 10 |
21 |
},
|
22 |
score: { |
23 |
fontSize: 40, |
24 |
fontWeight: 'bold' |
25 |
}
|
26 |
});
|
Una vez más, sólo un simple Mostrar componente con una vista de texto y algunos estilo básico.
Componente de Tarjeta
El componente de la tarjeta (components/Card.js) mostrará las cartas. Estas tarjetas utilizan iconos del conjunto de iconos de vector de Expo. Esta es una de las características que vienen directamente de la caja cuando usas Expo: incluye los iconos de conjuntos de icono como FontAwesome, Entypo y Ionicons.
En el código a continuación, puedes ver que estamos utilizando sólo FontAwesome. Tiene el icono que queremos para la visualización de estado de la tarjeta por defecto: un signo de interrogación. Como veremos más adelante en el componente principal de la aplicación, también usaremos los iconos de Entypo y Ionicons. La referencia a las fuentes del icono pasará a este componente, por lo que no es necesario especificar aquí:
1 |
import React from 'react'; |
2 |
import { StyleSheet, Text, View, TouchableHighlight } from 'react-native'; |
3 |
import { FontAwesome } from '@expo/vector-icons'; // use FontAwesome from the expo vector icons |
En el método render(), sólo utilizamos la fuente y el icono pasada como apoyos si se abre la tarjeta. Por defecto, sólo mostrará el icono de signo de interrogación de FontAwesome. Pero si la tarjeta está abierta, utilizará el icono fuente, icono y color que se pasa como apoyos.
Cada una de las tarjetas puede ser aprovechada. Cuando aprovechado, se ejecutará la función clickCard(), que es pasado a través de los apoyos. Más adelante se verá la función de lo que hace, pero de momento, sólo sé que actualiza el estado para mostrar el icono de la tarjeta:
1 |
export default class Card extends React.Component { |
2 |
|
3 |
render() { |
4 |
|
5 |
let CardSource = FontAwesome; // set FontAwesome as the default icon source |
6 |
let icon_name = 'question-circle'; |
7 |
let icon_color = '#393939'; |
8 |
|
9 |
if(this.props.is_open){ |
10 |
CardSource = this.props.src; |
11 |
icon_name = this.props.name; |
12 |
icon_color = this.props.color; |
13 |
}
|
14 |
|
15 |
return ( |
16 |
<View style={styles.card}> |
17 |
<TouchableHighlight onPress={this.props.clickCard} activeOpacity={0.75} underlayColor={"#f1f1f1"}> |
18 |
<CardSource |
19 |
name={icon_name} |
20 |
size={50} |
21 |
color={icon_color} |
22 |
/> |
23 |
</TouchableHighlight> |
24 |
</View> |
25 |
);
|
26 |
}
|
27 |
}
|
No te olvides de añadir los estilos:
1 |
const styles = StyleSheet.create({ |
2 |
card: { |
3 |
flex: 1, |
4 |
alignItems: 'center' |
5 |
},
|
6 |
card_text: { |
7 |
fontSize: 50, |
8 |
fontWeight: 'bold' |
9 |
}
|
10 |
});
|
Ayudantes
También utilizaremos una función auxiliar denominada shuffle(). Esto nos permite ordenar la matriz de las tarjetas en orden aleatorio para que su orden será diferente cada vez que se reinicia el juego:
1 |
Array.prototype.shuffle = function() { |
2 |
var i = this.length, j, temp; |
3 |
if(i == 0) return this; |
4 |
while(--i){ |
5 |
j = Math.floor(Math.random() * (i + 1)); |
6 |
temp = this[i]; |
7 |
this[i] = this[j]; |
8 |
this[j] = temp; |
9 |
}
|
10 |
return this; |
11 |
}
|
Componente Principal
El componente principal (App.js) contiene la lógica de la aplicación principal y trae todo junto. Empezar por incluyendo los paquetes reaccionan y Expo que vamos a usar. Esta vez estamos utilizando todas las fuentes de icono de los iconos de vector de Expo:
1 |
import React from 'react'; |
2 |
import { StyleSheet, View, Button } from 'react-native'; |
3 |
import { Ionicons, FontAwesome, Entypo } from '@expo/vector-icons'; |
A continuación, se incluyen los componentes y el ayudante que creamos anteriormente:
1 |
import Header from './components/Header'; |
2 |
import Score from './components/Score'; |
3 |
import Card from './components/Card'; |
4 |
|
5 |
import helpers from './helpers'; |
Dentro del constructor, primero creamos la matriz que representa las tarjetas únicas. src es la fuente del icono, name es el nombre del icono (usted puede encontrar los nombres en GitHub si desea utilizar otros iconos) y el color es, naturalmente, el color del icono:
1 |
export default class App extends React.Component { |
2 |
|
3 |
constructor(props) { |
4 |
super(props); |
5 |
// bind the functions to the class
|
6 |
this.renderCards = this.renderCards.bind(this); |
7 |
this.resetCards = this.resetCards.bind(this); |
8 |
|
9 |
// icon sources
|
10 |
let sources = { |
11 |
'fontawesome': FontAwesome, |
12 |
'entypo': Entypo, |
13 |
'ionicons': Ionicons |
14 |
};
|
15 |
|
16 |
// the unique icons to be used
|
17 |
let cards = [ |
18 |
{
|
19 |
src: 'fontawesome', |
20 |
name: 'heart', |
21 |
color: 'red' |
22 |
},
|
23 |
{
|
24 |
src: 'entypo', |
25 |
name: 'feather', |
26 |
color: '#7d4b12' |
27 |
},
|
28 |
{
|
29 |
src: 'entypo', |
30 |
name: 'flashlight', |
31 |
color: '#f7911f' |
32 |
},
|
33 |
{
|
34 |
src: 'entypo', |
35 |
name: 'flower', |
36 |
color: '#37b24d' |
37 |
},
|
38 |
{
|
39 |
src: 'entypo', |
40 |
name: 'moon', |
41 |
color: '#ffd43b' |
42 |
},
|
43 |
{
|
44 |
src: 'entypo', |
45 |
name: 'youtube', |
46 |
color: '#FF0000' |
47 |
},
|
48 |
{
|
49 |
src: 'entypo', |
50 |
name: 'shop', |
51 |
color: '#5f5f5f' |
52 |
},
|
53 |
{
|
54 |
src: 'fontawesome', |
55 |
name: 'github', |
56 |
color: '#24292e' |
57 |
},
|
58 |
{
|
59 |
src: 'fontawesome', |
60 |
name: 'skype', |
61 |
color: '#1686D9' |
62 |
},
|
63 |
{
|
64 |
src: 'fontawesome', |
65 |
name: 'send', |
66 |
color: '#1c7cd6' |
67 |
},
|
68 |
{
|
69 |
src: 'ionicons', |
70 |
name: 'ios-magnet', |
71 |
color: '#d61c1c' |
72 |
},
|
73 |
{
|
74 |
src: 'ionicons', |
75 |
name: 'logo-facebook', |
76 |
color: '#3C5B9B' |
77 |
}
|
78 |
];
|
79 |
|
80 |
// next: add code creating the clone and setting the cards in the state
|
81 |
}
|
82 |
|
83 |
}
|
Tenga en cuenta que en vez de directamente la src como FontAwesome, Entypo o Ionicons para cada uno de los objetos, estamos utilizando los nombres de propiedad en el objeto los recursos. Esto es porque necesitamos crear una copia de la matriz de las tarjetas en orden para que cada tarjeta tiene un par. Crear una copia mediante métodos de matriz como slice() creará una copia de la matriz, pero el problema es que una vez que los objetos individuales se modifican en la copia o la original, ambas matrices son también modificadas.
Esto nos lleva a la solución de abajo que es para crear un objeto completamente nuevo por convertir la matriz de cards en cadena y luego de análisis para convertir a una matriz. Esta es la razón por qué estamos utilizando cadenas puesto que las funciones no se puede convertir en cadenas. Luego, combinamos los dos para llegar a la matriz, que contiene todas las cartas que necesitamos:
1 |
let clone = JSON.parse(JSON.stringify(cards)); // create a completely new array from the array of cards |
2 |
|
3 |
this.cards = cards.concat(clone); // combine the original and the clone |
A continuación, pasar por esa matriz generar un ID único para cada uno, establecer el origen del icono y ponerlo a un estado cerrado por defecto:
1 |
// add the ID, source and set default state for each card
|
2 |
this.cards.map((obj) => { |
3 |
let id = Math.random().toString(36).substring(7); |
4 |
obj.id = id; |
5 |
obj.src = sources[obj.src]; |
6 |
obj.is_open = false; |
7 |
});
|
Ordenar las tarjetas al azar y establecer el estado predeterminado:
1 |
this.cards = this.cards.shuffle(); // sort the cards randomly |
2 |
|
3 |
// set the default state
|
4 |
this.state = { |
5 |
current_selection: [], // this array will contain an array of card objects which are currently selected by the user. This will only contain two objects at a time. |
6 |
selected_pairs: [], // the names of the icons. This array is used for excluding them from further selection |
7 |
score: 0, // default user score |
8 |
cards: this.cards // the shuffled cards |
9 |
}
|
El método render() representa el encabezado, cartas, puntuación y el botón para reiniciar el juego. Está utilizando la función renderRows() para representar las filas de la tarjeta individual. La pantalla tendrá seis filas que contiene cuatro cartas:
1 |
render() { |
2 |
return ( |
3 |
<View style={styles.container}> |
4 |
<Header /> |
5 |
<View style={styles.body}> |
6 |
{
|
7 |
this.renderRows.call(this) |
8 |
}
|
9 |
</View> |
10 |
<Score score={this.state.score} /> |
11 |
<Button |
12 |
onPress={this.resetCards} |
13 |
title="Reset" |
14 |
color="#008CFA" |
15 |
/>
|
16 |
</View> |
17 |
);
|
18 |
}
|
Aquí está el código para la función renderRows(). Esto utiliza la función getRowContents(), que es responsable de crear una matriz de matrices con cuatro artículos. Esto nos permite procesar cada fila y luego usar otra función para las tarjetas de representación para cada iteración de la función map():
1 |
renderRows() { |
2 |
|
3 |
let contents = this.getRowContents(this.state.cards); |
4 |
return contents.map((cards, index) => { |
5 |
return ( |
6 |
<View key={index} style={styles.row}> |
7 |
{ this.renderCards(cards) } |
8 |
</View> |
9 |
);
|
10 |
});
|
11 |
|
12 |
}
|
Esta es la función de getRowContents():
1 |
getRowContents(cards) { |
2 |
let contents_r = []; |
3 |
let contents = []; |
4 |
let count = 0; |
5 |
cards.forEach((item) => { |
6 |
count += 1; |
7 |
contents.push(item); |
8 |
if(count == 4){ |
9 |
contents_r.push(contents) |
10 |
count = 0; |
11 |
contents = []; |
12 |
}
|
13 |
});
|
14 |
|
15 |
return contents_r; |
16 |
}
|
El siguiente es la función de renderCards(). Esto acepta la matriz de objetos de la tarjeta y representa mediante el componente cards. Lo único que tenemos que hacer es pasar las propiedades individuales de cada objeto de la tarjeta como apoyos. Esto entonces se utiliza para representar el icono correcto, como has visto en el código para el componente cards. La función clickCard() se pasa también como un apoyo. La tarjeta de identificación se pasa a esa función para que la tarjeta única se puede identificar y actualizada:
1 |
renderCards(cards) { |
2 |
return cards.map((card, index) => { |
3 |
return ( |
4 |
<Card |
5 |
key={index} |
6 |
src={card.src} |
7 |
name={card.name} |
8 |
color={card.color} |
9 |
is_open={card.is_open} |
10 |
clickCard={this.clickCard.bind(this, card.id)} |
11 |
/> |
12 |
);
|
13 |
});
|
14 |
}
|
Dentro de la función clickCard(), obtener los detalles de la tarjeta seleccionada y comprobar si deben ser procesado más:
1 |
clickCard(id) { |
2 |
let selected_pairs = this.state.selected_pairs; |
3 |
let current_selection = this.state.current_selection; |
4 |
let score = this.state.score; |
5 |
|
6 |
// get the index of the currently selected card
|
7 |
let index = this.state.cards.findIndex((card) => { |
8 |
return card.id == id; |
9 |
});
|
10 |
|
11 |
let cards = this.state.cards; |
12 |
|
13 |
// the card shouldn't already be opened and is not on the array of cards whose pairs are already selected
|
14 |
if(cards[index].is_open == false && selected_pairs.indexOf(cards[index].name) === -1){ |
15 |
|
16 |
// next: add code for processing the selected card
|
17 |
|
18 |
}
|
19 |
|
20 |
}
|
Ahora vamos a rellenar el código para el manejo de una tarjeta seleccionada.
En primer lugar, abrimos la tarjeta y añadir a la gama de tarjetas actualmente seleccionadas:
1 |
cards[index].is_open = true; |
2 |
|
3 |
current_selection.push({ |
4 |
index: index, |
5 |
name: cards[index].name |
6 |
});
|
7 |
|
8 |
// next: add code for determining whether the user has selected the correct pair or not
|
Una vez que hay dos elementos en la matriz de cartas seleccionados, comprobamos si los nombres de icono son los mismos. Si son entonces significa el usuario ha seleccionado el par correcto. Si no son iguales entonces es un par incorrecto. En ese caso, cerramos la primera tarjeta que seleccionó y luego añadir un poco de retraso antes de cerrar la segunda tarjeta. (De esta manera el usuario puede ver el icono de la tarjeta antes de que revierta al estado cerrado.)
1 |
if(current_selection.length == 2){ |
2 |
if(current_selection[0].name == current_selection[1].name){ |
3 |
score += 1; // increment the score |
4 |
selected_pairs.push(cards[index].name); |
5 |
}else{ |
6 |
cards[current_selection[0].index].is_open = false; // close the first |
7 |
|
8 |
// delay closing the currently selected card by half a second.
|
9 |
setTimeout(() => { |
10 |
cards[index].is_open = false; |
11 |
this.setState({ |
12 |
cards: cards |
13 |
});
|
14 |
}, 500); |
15 |
}
|
16 |
|
17 |
current_selection = []; |
18 |
}
|
19 |
|
20 |
// next: add code for updating the state
|
Lo último que debemos hacer en el controlador de evento click es actualizar el estado para reflejar los cambios en la interfaz de usuario:
1 |
this.setState({ |
2 |
score: score, |
3 |
cards: cards, |
4 |
current_selection: current_selection |
5 |
});
|
Una función relacionada es el controlador de evento de reset. Cuando se golpea ligeramente el botón reset, nos simplemente restaurar el estado predeterminado cerrando todas las cartas y arrastrando los pies.
1 |
resetCards() { |
2 |
// close all cards
|
3 |
let cards = this.cards.map((obj) => { |
4 |
obj.is_open = false; |
5 |
return obj; |
6 |
});
|
7 |
|
8 |
cards = cards.shuffle(); // re-shuffle the cards |
9 |
|
10 |
// update to default state
|
11 |
this.setState({ |
12 |
current_selection: [], |
13 |
selected_pairs: [], |
14 |
cards: cards, |
15 |
score: 0 |
16 |
});
|
17 |
}
|
Por último, vamos a añadir unos estilos básicos para hacer que nuestra aplicación se ven bien.
1 |
const styles = StyleSheet.create({ |
2 |
container: { |
3 |
flex: 1, |
4 |
alignSelf: 'stretch', |
5 |
backgroundColor: '#fff' |
6 |
},
|
7 |
row: { |
8 |
flex: 1, |
9 |
flexDirection: 'row' |
10 |
},
|
11 |
body: { |
12 |
flex: 18, |
13 |
justifyContent: 'space-between', |
14 |
padding: 10, |
15 |
marginTop: 20 |
16 |
}
|
17 |
});
|
Prueba la Aplicación
Desde el servidor de desarrollo de la Expo ha estado funcionando todo este tiempo, todos los cambios deben enviarse a su dispositivo móvil con recarga directo. Probar la aplicación y asegúrese de que funciona como se supone a.
Conclusión
¡Eso es todo! En este tutorial has aprendido cómo utilizar la Expo XDE para conectar rápidamente una aplicación React Native. Expo es una buena manera para empezar a desarrollar aplicaciones React Native porque elimina la necesidad de instalar un montón de software que es a menudo una causa de frustración, especialmente para los principiantes. También proporciona herramientas que hace muy fácil de obtener una vista previa de la aplicación mientras se está desarrollando. Asegúrese de comprobar los recursos mencionados en el sitio web de Expo si usted quiere aprender más.
Y mientras tanto, echa un vistazo a algunos de nuestros otros posts sobre desarrollo de aplicaciones React Native!


React NativeEjemplos Prácticos de Animación en React NativeAncheta de Wernher-Bel

GraphQLCódificar una Aplicación con GraphQL, React Native y AWS AppSync: Back-EndDabit Nader

Desarrollo MóvilHerramientas Para el Desarrollo React NativeAncheta de Wernher-Bel

Reacción nativaEmpezar Con una Plantilla de Aplicación React NativeAncheta de Wernher-Bel



