d
Probar y ampliar nuestra aplicación
Ahora que hemos establecido una buena base para nuestro proyecto, es hora de empezar a ampliarlo. En esta sección puede poner en práctica todo el conocimiento de React Native que ha adquirido hasta ahora. Además de expandir nuestra aplicación, cubriremos algunas áreas nuevas, como pruebas y recursos adicionales.
Prueba de aplicaciones React Native
Para comenzar a probar código de cualquier tipo, lo primero que necesitamos es un marco de prueba, que podemos usar para ejecutar un conjunto de casos de prueba e inspeccionar sus resultados. Para probar una aplicación de JavaScript, Jest es un candidato popular para dicho marco de prueba. Para probar una aplicación React Native basada en Expo con Jest, Expo proporciona un conjunto de configuración de Jest en forma de jest-expo Preestablecido. Para usar ESLint en los archivos de prueba de Jest, también necesitamos el complemento eslint-plugin-jest para ESLint. Comencemos instalando los paquetes:
npm install --save-dev jest jest-expo eslint-plugin-jest
Para usar el ajuste preestablecido de jest-expo en Jest, necesitamos agregar la siguiente configuración de Jest al archivo package.json junto con el script test:
{
// ...
"scripts": {
// other scripts...
"test": "jest" },
"jest": { "preset": "jest-expo", "transform": { "^.+\\.jsx?$": "babel-jest" }, "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*|react-router-native)" ] }, // ...
}
La opción transform le dice a Jest que transforme los archivos .js y .jsx con compilador Babel. La opción transformIgnorePatterns es para ignorar ciertos directorios en el directorio node_modules mientras se transforman archivos. Esta configuración de Jest es casi idéntica a la propuesta en la documentación de Expo. Para usar el complemento eslint-plugin-jest en ESLint, debemos incluirlo en la matriz de complementos y extensiones en el archivo .eslintrc:
{
"plugins": ["react", "jest"],
"extends": ["eslint:recommended", "plugin:react/recommended", "plugin:jest/recommended"], "parser": "babel-eslint",
"env": {
"browser": true
},
"rules": {
"react/prop-types": "off"
}
}
Para ver que la configuración está funcionando, cree un directorio __tests\ en el directorio src y en el directorio creado cree un archivo example.js. En ese archivo, agregue esta simple prueba:
describe('Example', () => {
it('works', () => {
expect(1).toBe(1);
});
});
Ahora, ejecutemos nuestra prueba de ejemplo ejecutando npm test. La salida del comando debe indicar que se pasó la prueba ubicada en el archivo src/__tests\/example.js.
Organización de pruebas
Organizar archivos de prueba en un solo directorio __tests__ es un método para organizar las pruebas. Al elegir este enfoque, se recomienda colocar los archivos de prueba en sus subdirectorios correspondientes al igual que el código en sí. Esto significa que, por ejemplo, las pruebas relacionadas con los componentes están en el directorio components, las pruebas relacionadas con las utilidades están en las utils directorio, y así sucesivamente. Esto dará como resultado la siguiente estructura:
src/
__tests__/
components/
AppBar.js
RepositoryList.js
...
utils/
authStorage.js
...
...
Otro enfoque es organizar las pruebas cerca de la implementación. Esto significa que, por ejemplo, el archivo de prueba que contiene las pruebas para el componente AppBar está en el mismo directorio que el código del componente. Esto dará como resultado la siguiente estructura:
src/
components/
AppBar/
AppBar.test.jsx
index.jsx
...
...
En este ejemplo, el código del componente está en el archivo index.jsx y la prueba en el archivo AppBar.test.jsx. Tenga en cuenta que para Jest encontrar sus archivos de prueba, debe colocarlos en un directorio __tests__, use .test o .spec sufijo, o configurar manualmente los patrones globales.
Prueba de componentes
Ahora que hemos logrado configurar Jest y ejecutar una prueba muy simple, es hora de descubrir cómo probar los componentes. Como sabemos, probar componentes requiere una forma de serializar la salida de render de un componente y simular la activación de diferentes tipos de eventos, como presionar un botón. Para estos propósitos, existe la familia Testing Library, que proporciona bibliotecas para probar componentes de interfaz de usuario en diferentes plataformas. Todas estas bibliotecas comparten una API similar para probar los componentes de la interfaz de usuario de una manera centrada en el usuario.
En la parte 5 nos familiarizamos con una de estas liberías, la React Testing Library. Desafortunadamente, esta librería solo es adecuada para probar aplicaciones web React. Afortunadamente, existe una contraparte de React Native para esta librería, que es la React Native Testing Library. Esta es la librería que usaremos mientras probamos los componentes de nuestra aplicación React Native. La buena noticia es que estas bibliotecas comparten una API muy similar, por lo que no hay demasiados conceptos nuevos que aprender. Además de la biblioteca de pruebas React Native, necesitamos un conjunto de comparadores Jest específicos de React Native, como toHaveTextContent y toHaveProp. Estos comparadores los proporciona la librería jest-native. Antes de entrar en detalles, instalemos estos paquetes:
npm install --save-dev @testing-library/react-native @testing-library/jest-native
Para poder usar estos comparadores necesitamos extender el objeto expect de Jest. Esto se puede hacer usando un archivo de configuración global. Cree un archivo setupTests.js en el directorio raíz de su proyecto, es decir, el mismo directorio donde se encuentra el archivo package.json. En ese archivo agregue la siguiente línea:
import '@testing-library/jest-native/extend-expect';
A continuación, configure este archivo como un archivo de instalación en la configuración de Jest en el archivo package.json (tenga en cuenta que el <rootDir> en la ruta es intencional y no es necesario reemplazarlo):
{
// ...
"jest": {
"preset": "jest-expo",
"transform": {
"^.+\\.jsx?$": "babel-jest"
},
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*|react-router-native)"
],
"setupFilesAfterEnv": ["<rootDir>/setupTests.js"] }
// ...
}
Los conceptos principales de React Native Testing Library son las consultas y disparando eventos. Las consultas se utilizan para extraer un conjunto de nodos del componente que se representa mediante la función render. Las consultas son útiles en las pruebas donde esperamos, por ejemplo, que algún texto, como el nombre de un repositorio, esté presente en el componente renderizado. Para obtener fácilmente nodos específicos, puede etiquetar los nodos con la propiedad testID y consultarla con la función getByTestId. Cada componente principal de React Native acepta el prop testID. A continuación, se muestra un ejemplo de cómo utilizar las consultas:
import React from 'react';
import { Text, View } from 'react-native';
import { render } from '@testing-library/react-native';
const Greeting = ({ name }) => {
return (
<View>
{/* This node is tagged with the testID prop */}
<Text testID="greetingText">Hello {name}!</Text>
</View>
);
};
describe('Greeting', () => {
it('renders a greeting message based on the name prop', () => {
const { debug, getByTestId } = render(<Greeting name="Kalle" />);
debug();
expect(getByTestId('greetingText')).toHaveTextContent('Hello Kalle!');
});
});
La función render devuelve las consultas y ayudantes adicionales, como la función debug. La función debug imprime el árbol React renderizado en un formato fácil de usar. Úselo si no está seguro de cómo se ve el árbol de React generado por la función render. Adquirimos el nodo Text etiquetado con el prop testID usando la función getByTestId. Para todas las consultas disponibles, consulte la documentación de React Native Testing Library . El comparador toHaveTextContent se usa para afirmar que el contenido textual del nodo es correcto. La lista completa de comparadores específicos de React Native disponibles se puede encontrar en la documentación de la biblioteca jest-native. La documentación de Jest contiene todos los comparadores de Jest universales.
El segundo concepto muy importante de React Native Testing Library es la activación de eventos. Podemos disparar un evento en un nodo provisto usando los métodos del objeto fireEvent. Esto es útil, por ejemplo, para escribir texto en un campo de texto o presionar un botón. Aquí hay un ejemplo de cómo probar el envío de un formulario simple:
import React, { useState } from 'react';
import { Text, TextInput, TouchableWithoutFeedback, View } from 'react-native';
import { render, fireEvent } from '@testing-library/react-native';
const Form = ({ onSubmit }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = () => {
onSubmit({ username, password });
};
return (
<View>
<View>
<TextInput
value={username}
onChangeText={(text) => setUsername(text)}
placeholder="Username"
testID="usernameField"
/>
</View>
<View>
<TextInput
value={password}
onChangeText={(text) => setPassword(text)}
placeholder="Password"
testID="passwordField"
/>
</View>
<View>
<TouchableWithoutFeedback onPress={handleSubmit} testID="submitButton">
<Text>Submit</Text>
</TouchableWithoutFeedback>
</View>
</View>
);
};
describe('Form', () => {
it('calls function provided by onSubmit prop after pressing the submit button', () => {
const onSubmit = jest.fn();
const { getByTestId } = render(<Form onSubmit={onSubmit} />);
fireEvent.changeText(getByTestId('usernameField'), 'kalle');
fireEvent.changeText(getByTestId('passwordField'), 'password');
fireEvent.press(getByTestId('submitButton'));
expect(onSubmit).toHaveBeenCalledTimes(1);
// onSubmit.mock.calls[0][0] contains the first argument of the first call
expect(onSubmit.mock.calls[0][0]).toEqual({
username: 'kalle',
password: 'password',
});
});
});
En esta prueba, queremos probar que después de completar los campos del formulario usando el método fireEvent.changeText y presionar el botón enviar usando el método fireEvent.press, La función de devolución de llamada onSubmit se llama correctamente. Para inspeccionar si se llama a la función onSubmit y con qué argumentos, podemos usar una función simulada. Las funciones simuladas son funciones con un comportamiento preprogramado, como un valor de retorno específico. Además, podemos crear expectativas para las funciones simuladas como "esperar que la función simulada se haya llamado una vez". La lista completa de expectativas disponibles se puede encontrar en la documentación de espera de Jest.
Antes de adentrarse más en el mundo de las pruebas de aplicaciones React Native, juegue con estos ejemplos agregando un archivo de prueba en el directorio __tests__ que creamos anteriormente.
Manejo de dependencias en pruebas
Los componentes de los ejemplos anteriores son bastante fáciles de probar porque son más o menos puros. Los componentes puros no dependen de efectos secundarios como las solicitudes de red o el uso de alguna API nativa como AsyncStorage. El componente Form es mucho menos puro que el componente Greeting porque sus cambios de estado pueden contarse como un efecto secundario. Sin embargo, probarlo no es demasiado difícil.
A continuación, echemos un vistazo a una estrategia para probar componentes con efectos secundarios. Escojamos el componente RepositoryList de nuestra aplicación como ejemplo. Por el momento, el componente tiene un efecto secundario, que es una consulta GraphQL para obtener los repositorios revisados. La implementación actual del componente RepositoryList se parece a esto:
const RepositoryList = () => {
const { repositories } = useRepositories();
const repositoryNodes = repositories
? repositories.edges.map((edge) => edge.node)
: [];
return (
<FlatList
data={repositoryNodes}
// ...
/>
);
};
export default RepositoryList;
El único efecto secundario es el uso del hook useRepositories, que envía una consulta GraphQL. Hay varias formas de probar este componente. Una forma es burlarse de las respuestas del Cliente Apollo como se indica en la documentación del Cliente Apollo. Una forma más sencilla es asumir que el hook useRepositories funciona según lo previsto (preferiblemente probándolo) y extraer el código "puro" de los componentes en otro componente, como el RepositoryListContainer componente:
export const RepositoryListContainer = ({ repositories }) => {
const repositoryNodes = repositories
? repositories.edges.map((edge) => edge.node)
: [];
return (
<FlatList
data={repositoryNodes}
// ...
/>
);
};
const RepositoryList = () => {
const { repositories } = useRepositories();
return <RepositoryListContainer repositories={repositories} />;
};
export default RepositoryList;
Ahora, el componente RepositoryList contiene solo los efectos secundarios y su implementación es bastante simple. Podemos probar el componente RepositoryListContainer proporcionándole datos de repositorio paginados a través de la propiedad repositories y comprobando que el contenido renderizado tenga la información correcta. Esto se puede lograr etiquetando los nodos del componente RepositoryItem requerido con los props testID.
Ampliando nuestra aplicación
Es hora de poner en práctica todo lo que hemos aprendido hasta ahora y empezar a ampliar nuestra aplicación. Nuestra aplicación aún carece de algunas características importantes, como revisar un repositorio y registrar un usuario. Los próximos ejercicios se centrarán en estas características esenciales.
Paginación basada en cursor
Cuando una API devuelve una lista ordenada de elementos de alguna colección, generalmente devuelve un subconjunto de todo el conjunto de elementos para reducir el ancho de banda requerido y disminuir el uso de memoria de las aplicaciones cliente. El subconjunto deseado de elementos se puede parametrizar para que el cliente pueda solicitar, por ejemplo, los primeros veinte elementos de la lista después de algún índice. Esta técnica se conoce comúnmente como paginación. Cuando se pueden solicitar elementos después de un elemento determinado definido por un cursor, estamos hablando de paginación basada en cursor.
Por tanto, el cursor es solo una presentación serializada de un elemento en una lista ordenada. Echemos un vistazo a los repositorios paginados devueltos por la consulta repositories utilizando la siguiente consulta:
{
repositories(first: 2) {
totalCount
edges {
node {
id
fullName
createdAt
}
cursor
}
pageInfo {
endCursor
startCursor
hasNextPage
}
}
}
El primer argumento le dice a la API que devuelva solo los dos primeros repositorios. Aquí hay un ejemplo de un resultado de la consulta:
{
"data": {
"repositories": {
"totalCount": 10,
"edges": [
{
"node": {
"id": "zeit.next.js",
"fullName": "zeit/next.js",
"createdAt": "2020-05-15T11:59:57.557Z"
},
"cursor": "WyJ6ZWl0Lm5leHQuanMiLDE1ODk1NDM5OTc1NTdd"
},
{
"node": {
"id": "zeit.swr",
"fullName": "zeit/swr",
"createdAt": "2020-05-15T11:58:53.867Z"
},
"cursor": "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10="
}
],
"pageInfo": {
"endCursor": "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10=",
"startCursor": "WyJ6ZWl0Lm5leHQuanMiLDE1ODk1NDM5OTc1NTdd",
"hasNextPage": true
}
}
}
}
En el objeto de resultado, tenemos la matriz edges que contiene elementos con los atributos node y cursor. Como sabemos, el nodo contiene el repositorio en sí. El cursor del otro es una representación codificada en Base64 del nodo. Contiene la identificación del repositorio y la fecha de creación del repositorio como una marca de tiempo. Esta es la información que necesitamos para señalar el elemento cuando se ordenan según el momento de creación del repositorio. pageInfo contiene información como el cursor del primer y último elemento de la matriz.
Digamos que queremos obtener el siguiente conjunto de elementos después del último elemento del conjunto actual, que es el repositorio "zeit/swr". Podemos establecer el argumento after de la consulta como el valor del endCursor así:
{
repositories(first: 2, after: "WyJ6ZWl0LnN3ciIsMTU4OTU0MzkzMzg2N10=") {
totalCount
edges {
node {
id
fullName
createdAt
}
cursor
}
pageInfo {
endCursor
startCursor
hasNextPage
}
}
}
Ahora que tenemos los siguientes dos elementos y podemos seguir haciendo esto hasta que hasNextPage tenga el valor false, lo que significa que hemos llegado al final de la lista. Para profundizar en la paginación basada en el cursor, lee el artículo de Shopify Paginación con cursores relativos. Proporciona grandes detalles sobre la implementación en sí y los beneficios sobre la paginación tradicional basada en índices.
Desplazamiento infinito
Las listas de desplazamiento vertical en aplicaciones móviles y de escritorio se implementan comúnmente mediante una técnica llamada desplazamiento infinito. El principio del desplazamiento infinito es bastante simple:
- Obtener el conjunto inicial de elementos
- Cuando el usuario alcanza el último elemento, recupera el siguiente conjunto de elementos después del último elemento.
El segundo paso se repite hasta que el usuario se cansa de desplazarse o se excede algún límite de desplazamiento. El nombre "desplazamiento infinito" se refiere a la forma en que la lista parece ser infinita: el usuario puede seguir desplazándose y siguen apareciendo nuevos elementos en la lista.
Echemos un vistazo a cómo funciona esto en la práctica utilizando el hook useQuery del cliente Apollo. Apollo Client tiene una excelente documentación sobre la implementación de la paginación basada en cursor. Implementemos el desplazamiento infinito para la lista de repositorios revisados como ejemplo.
Primero, necesitamos saber cuándo el usuario ha llegado al final de la lista. Afortunadamente, el componente FlatList tiene un prop onEndReached, que llamará a la función proporcionada una vez que el usuario se haya desplazado hasta el último elemento de la lista. Puede cambiar la anticipación con la que se llama a la devolución de llamada onEndReach usando el prop onEndReachedThreshold. Modifique el componente FlatList del componente RepositoryList para que llame a una función una vez que se alcance el final de la lista:
export const RepositoryListContainer = ({
repositories,
onEndReach,
/* ... */,
}) => {
const repositoryNodes = repositories
? repositories.edges.map((edge) => edge.node)
: [];
return (
<FlatList
data={repositoryNodes}
// ...
onEndReached={onEndReach}
onEndReachedThreshold={0.5}
/>
);
};
const RepositoryList = () => {
// ...
const { repositories } = useRepositories(/* ... */);
const onEndReach = () => {
console.log('You have reached the end of the list');
};
return (
<RepositoryListContainer
repositories={repositories}
onEndReach={onEndReach}
// ...
/>
);
};
export default RepositoryList;
Intente desplazarse hasta el final de la lista de repositorios revisados y debería ver el mensaje en los registros.
A continuación, necesitamos buscar más repositorios una vez que se llega al final de la lista. Esto se puede lograr utilizando la función fetchMore proporcionada por el hook useQuery. Modifiquemos el hook useRepositories para que devuelva una función fetchMore decorada, que llama a la función fetchMore real con el endCursor y actualiza la consulta correctamente con los datos obtenidos:
const useRepositories = (variables) => {
const { data, loading, fetchMore, ...result } = useQuery(GET_REPOSITORIES, {
variables,
// ...
});
const handleFetchMore = () => {
const canFetchMore =
!loading && data && data.repositories.pageInfo.hasNextPage;
if (!canFetchMore) {
return;
}
fetchMore({
query: GET_REPOSITORIES,
variables: {
after: data.repositories.pageInfo.endCursor,
...variables,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const nextResult = {
repositories: {
...fetchMoreResult.repositories,
edges: [
...previousResult.repositories.edges,
...fetchMoreResult.repositories.edges,
],
},
};
return nextResult;
},
});
};
return {
repositories: data ? data.repositories : undefined,
fetchMore: handleFetchMore,
loading,
...result,
};
};
Asegúrese de tener los campos pageInfo y cursor en su consulta de repositories como se describe en los ejemplos de paginación. También deberá incluir los argumentos after y first para la consulta.
La función handleFetchMore llamará a la función fetchMore del Cliente Apollo si hay más elementos para recuperar, lo cual está determinado por la propiedad hasNextPage. También queremos evitar la recuperación de más elementos si la recuperación ya está en proceso. En este caso, loading será true. En la función fetchMore proporcionamos a la consulta una variable after, que recibe el último valor endCursor. En updateQuery fusionaremos los bordes anteriores con los bordes obtenidos y actualizaremos la consulta para que pageInfo contenga la información más reciente.
El último paso es llamar a la función fetchMore en el manejador onEndReach:
const RepositoryList = () => {
// ...
const { repositories, fetchMore } = useRepositories({
first: 8,
// ...
});
const onEndReach = () => {
fetchMore();
};
return (
<RepositoryListContainer
repositories={repositories}
onEndReach={onEndReach}
// ...
/>
);
};
export default RepositoryList;
Utilice un valor de argumento first relativamente pequeño, como 8, mientras prueba el desplazamiento infinito. De esta forma, no es necesario revisar demasiados repositorios. Es posible que se enfrente a un problema de que se llame al controlador onEndReach inmediatamente después de que se cargue la vista. Lo más probable es que esto se deba a que la lista contiene tan pocos repositorios que se llega al final de la lista inmediatamente. Puede solucionar este problema aumentando el valor del argumento first. Una vez que esté seguro de que el desplazamiento infinito está funcionando, no dude en utilizar un valor mayor para el argumento first.
Recursos adicionales
A medida que nos acercamos al final de esta parte, tomemos un momento para ver algunos recursos adicionales relacionados con React Native. Awesome React Native es una lista de recursos de React Native extremadamente completa, como liberías, tutoriales y artículos. Debido a que la lista es exhaustivamente larga, echemos un vistazo más de cerca a algunos de sus aspectos más destacados.
React Native Paper
Paper es una colección de componentes personalizables y listos para producción para React Native, siguiendo las pautas de Material Design de Google.
React Native Paper es para React Native lo que Material-UI es para las aplicaciones web de React. Ofrece una amplia gama de componentes de interfaz de usuario de alta calidad y compatibilidad con temas personalizados. Configurar React Native Paper para las aplicaciones React Native basadas en Expo es bastante simple, lo que hace posible su uso en el próximo ejercicios si quieres intentarlo.
Styled-components
Utilizando template literals etiquetados (una adición reciente a JavaScript) y el poder de CSS, los componentes con estilo le permiten escribir código CSS real para diseñar sus componentes. También elimina el mapeo entre componentes y estilos: ¡usar componentes como una construcción de estilo de bajo nivel no podría ser más fácil!
Styled-components es una librería para diseñar componentes de React usando CSS-in-JS técnica. En React Native ya estamos acostumbrados a definir los estilos de los componentes como un objeto JavaScript, por lo que CSS-in-JS no es un territorio tan inexplorado. Sin embargo, el enfoque de los componentes con estilo es bastante diferente de usar el método StyleSheet.create y el prop style.
En los componentes con estilo, los estilos de los componentes se definen con el componente utilizando una función llamada template litearal etiquetado o un Objeto JavaScript. Styled-components hace posible definir nuevas propiedades de estilo para el componente en función de sus props en tiempo de ejecución. Esto ofrece muchas posibilidades, como cambiar sin problemas entre un tema claro y uno oscuro. También tiene un soporte de temas completo . Aquí hay un ejemplo de cómo crear un componente Text con variaciones de estilo basadas en props:
import React from 'react';
import styled from 'styled-components/native';
import { css } from 'styled-components';
const FancyText = styled.Text`
color: grey;
font-size: 14px;
${({ isBlue }) =>
isBlue &&
css`
color: blue;
`}
${({ isBig }) =>
isBig &&
css`
font-size: 24px;
font-weight: 700;
`}
`;
const Main = () => {
return (
<>
<FancyText>Simple text</FancyText>
<FancyText isBlue>Blue text</FancyText>
<FancyText isBig>Big text</FancyText>
<FancyText isBig isBlue>
Big blue text
</FancyText>
</>
);
};
Debido a que los componentes con estilo procesan las definiciones de estilo, es posible utilizar una sintaxis de mayúsculas y minúsculas similar a CSS con los nombres de propiedad y las unidades en los valores de propiedad. Sin embargo, las unidades no tienen ningún efecto porque los valores de las propiedades no tienen unidades internas. Para obtener más información sobre los componentes con estilo, diríjase a la documentación.
React-spring
react-spring es una librería de animación basada en la física de spring que debería cubrir la mayoría de tus necesidades de animación relacionadas con la interfaz de usuario. Le brinda herramientas lo suficientemente flexibles para transmitir con confianza sus ideas en interfaces móviles.
React-spring es una librería que proporciona una hook API limpia para animar componentes React Native.
Navegación React
Enrutamiento y navegación para sus aplicaciones React Native
React Navigation es una librería de enrutamiento para React Native. Comparte algunas similitudes con la biblioteca React Router que hemos estado usando durante esta y partes anteriores. Sin embargo, a diferencia de React Router, React Navigation ofrece más funciones nativas, como gestos nativos y animaciones para la transición entre vistas.
Palabras de cierre
Eso es todo, nuestra aplicación está lista. ¡Buen trabajo! Hemos aprendido muchos conceptos nuevos durante nuestro viaje, como configurar nuestra aplicación React Native usando Expo, usar los componentes centrales de React Native y agregarles estilo, comunicarnos con el servidor y probar aplicaciones React Native. La última pieza del rompecabezas sería implementar la aplicación en Apple App Store y Google Play Store.
La implementación de la aplicación es completamente opcional y no es del todo trivial, porque también necesitas bifurcar e implementar la rate-repository-api. Para la propia aplicación React Native, primero debes crear compilaciones de iOS o Android siguiendo la documentación de Expo. Luego, puede cargar estas compilaciones en Apple App Store o Google Play Store. Expo tiene una documentación para esto también.