Notas de React Native
Tags: reactnative, cheatsheet, typescript, mobile
Published: 2023-09-19 18:38:05

## Crear proyecto
`npx create-react-app miApp` Crear proyecto
`npm start` Iniciar el proyecto en el navegador

## Crear proyecto con Expo Go
`npx create-expo-app miApp` Comando para crear proyecto
`npm start` Generar el QR para iniciar el proyecto, el QR debe leerse desde la app Expo 

## Crear proyecto con React Native CLI
`npx react-native init miApp` Crear proyecto
`npx react-native start` Iniciar Metro para correr el proyecto
`npx react-native run-android` Iniciar proyecto en Android
`npx react-native run-ios` Iniciar proyecto en iOS
`npx react-native log-ios` Acceder a los logs de iOS
`npx react-native log-android` Acceder a los logs de Android

### Comandos útiles 
`adb devices` Para ver los dispositivos conectados en donde podemos trabajar
`xcrun simctl list devices` Lista los dispositivos iOS que podemos usar

## Agregar ESLint
`npm i eslint --save-dev` Instalar ESLint para ayudarnos con problemas de sintaxis
`npm i @react-native-community/eslint-config --save-dev` Instalar ESLint de la comunidad
`npm i --save-dev --save-exact prettier` Instalar Prettier para formatear el código, hay que crear .prettierrc.js y ahi agregar las reglas 

## Acceder al menú de debug
En un dispositivo físico se puede agitar el dispositivo para acceder al menú.
Para un emulador en iOS, es con command+d 
Para un emulador en Android, es con command+m o control+m

## Archivos
Para crear archivos, hay que agregar la extensión `.tsx`
`index.tsx` Es el punto de entrada de la aplicación
`tsconfig.json` Están las reglas de como queremos que trabaje TypeScript  

## Tipado
`let variable: string;` Agregar una variable con un tipo string
`let variable: string = ‘Ejemplo’;` Asignar un valor a la variable
`let variable: string | number = 123;` La variable puede tomar un tipo string o un tipo number para su valor

## Elementos
`SafeAreaView` Contenedor que inicia la vista bajo la barra de estado
`View` Contenedor que no puede ser scrolleado, equivalente al ‘div’ en HTML
`Text` Contenedor de texto
`StatusBar` Permite hacer modificaciones en el status bar, como cambiar el color de fondo, ocultarlo, estilo, etc.
`ActivityIndicator` Permite poner el circulo de ‘cargando’ `<ActivityIndicator color=“red” size={20}/>`
`FlatList` Permite crear listas

## Estilos
### Estilos en línea
`<View style={{backgroundColor: ‘pink’}}>` Darle al View un background rosa

### Estilos con condiciones
Para agregar un estilo u otro dependiendo de si una condición se cumple:
```
style={(condicion) 
? styles.condicionVerdadera
: styles.condicionFalsa}
```

### StyleSheet
Debe importarse StyleSheet de la API de React Native y crear un objeto antes de exportar el componente, se crea de la siguiente manera:
```
const styles = StyleSheet.create({
	container: {
		backgroundColor: ‘pink’
	}
})
```
.
`<View style={styles.container}>` Para agregarle los estilos a un elemento
`<View style={[styles.container, styles.bgBlack]}>` Agregar varios estilos

### Diseño
*Box object model* Se refiere al alto, ancho, margen, padding y borde
*Position* Puede ser absoluta, relativa, etc.
*Flex box* Habla de la dirección, ubicación, alineamiento, proporciones, etc.

### Estilos en otro archivo
Podemos crear nuestro archivo de estilos:
```
import { StyleSheet } from "react-native";

const styles = StyleSheet.create({…});

export default styles;
```
Y usarlos normalmente en el archivo donde lo necesitemos, sin olvidar importarlo:
```
const App = () => {
  return (
    <SafeAreaView style={ styles.container }>…</SafeAreaView>
  )
}
```

### Interfaz
Sirven para poner reglas de validación a nuestros objetos.
```
interface Persona {
nombre: string,
edad: number,
direccion: {
		pais: string,
		estado: string;
	}
}
```
La parte de ‘dirección’ puede extraerse en una nueva interfaz.
`let persona1: Persona;` Se crea una variable que es del tipo ‘Persona’ de la interfaz creada.

## Props
Son datos que llegan como parámetros en la función.
`const App = (props: Props) => {…}`
Si de antemano sabemos cuáles serán las propiedades que vamos a recibir, podemos desestructurarlo y elegir solo las propiedades que necesitamos:
`const App = ({prop1, prop2}: Props) => {…}`

## Context y estado global de la App
Proporciona una forma de compartir datos entre componentes sin tener que pasar props a través de la jerarquía de componentes manualmente.
El context es como nuestro árbol de componentes.

*Ejemplo básico*
Aquí vamos a guardar la información del authState en la app para ser accedido por los hijos globalmente.

```
import { createContext } from "react";

// Define hoy will look like the general data
export interface AuthState {
    isLoggedIn: boolean;
    username?: string;
}

// Define which properties will be shared to the children, in case we don't want to
// add all of AuthState or we want to add more
export interface AuthContextProps {
    authState: AuthState,
    signIn: () => void;
}

// Initial state
export const authInitialState: AuthState = {
    isLoggedIn: false,
    username: undefined,
}

// Create context, it has the data that will be shared in all children components
export const AuthContext = createContext({} as AuthContextProps);

// State provider component
export const AuthProvider = ({children}: any) => {
    const [authState, dispatch] = useReducer(authReducer, authInitialState)

    const signIn = () => {
        dispatch({type: 'signIn'})
    }

    return (
        <AuthContext.Provider value={{
            authState,
            signIn
        }}>
            {children}
        </AuthContext.Provider>
    );
}
```

Podemos envolver App en una función que tenga el AuthProvider para que los elementos hijos tengan acceso a la información del AuthProvider:
```
const App = () => {
  return (
    <NavigationContainer>
      <AppState>
        <TabsNavigator />
      </AppState>
    </NavigationContainer>
  )
}

const AppState = ({children}: any) => {
  return (
    <AuthProvider>
      {children}
    </AuthProvider>
  )
}
```

Si queremos ejecutar un método de los definidos: 
```
const {authState, signIn} = useContext(AuthContext);
<Text>
{JSON.stringify(authState, null, 4)}
</Text>
{authState.isLoggedIn && <Button title='Sign in' onPress={signIn} />}
```

Y hay que manejar el método en el authReducer, el *payload* funciona para mandar más información a la acción:
```
import { AuthState } from "./AuthContext";

type AuthAction = 
    { type: 'signIn' } |
    { type: 'logout', payload: string };

// Generates a new state
export const authReducer = (state:AuthState, action: AuthAction):AuthState => {
    switch (action.type) {
        case 'signIn':
            return {
                ...state,
                isLoggedIn: true,
                username: 'no-username'
            }
        default:
            return state;
    }
}
```

*Imprimir los datos*
Desde alguno de los componentes hijos podemos usar el hook de useContext:
`const {authState} = useContext(AuthContext);`
E imprimir su valor
`<Text>{JSON.stringify(authState, null, 4)}</Text>`

## Funciones
`const operacion = () => {…}` Declarar una función 
`const operacion = (): number => {…}` Declarar una función que retorna un dato de tipo number
`const operacion = (a: string): number => {…}` Declarar una función que retorna un dato de tipo number y recibe un parámetro ‘a’ de tipo string
`let resultado = operacion(“hola”);` Llamar a la función

## Carpetas
Hay que crear una carpeta ‘src’ en la raíz del proyecto en donde hay que agregar el código/carpetas que necesitemos. Dentro de esa carpeta, podemos agregar las siguientes carpetas:
- API: Para almacenar lo referente a peticiones
- Assets: Guarda imágenes, videos, audios, etc.
- Components: Almacenar archivos necesarios para hooks, API, etc.
- Hooks: Aquí se guardan los hooks personalizados.
- Interfaces: Para archivos que muestran el tipado.
- Navigation: Contiene los archivos necesarios para la navegación. - Screens: Para almacenar las vistas del proyecto.
- Theme: Almacena los estilos globales y sus configuraciones.

### Componentes
Podemos crear un archivo llamado Navbar.tsx y ahi crear la vista para un navbar, para utilizarlo en el archivo App.tsx hay que agregar su etiqueta e importar el archivo:
`<Navbar />`
A esos componentes podemos enviarles props:
`<Navbar title=“Hola” />`
Pero en el archivo Navbar.tsx tambien hay que definir cuales propiedades van a llegar:
`const Navbar = (props: String) => {…}` o `const Navbar = ({title}: String) => {…}`
`const Navbar = ({title?}: String) => {…}` Para agregar propiedades opcionales se agrega un ‘?’
`const Navbar = ({title? = ‘Hola’}: String) => {…}` Se le da un valor por defecto a la propiedad, para en caso de que no reciba nada

## Hooks
### useState
`const [valor, setValor] = useState(0);` Crear una variable de tipo number con valor inicial de 0
`setValor(10);` Cambiamos el valor de ‘valor’ a 10

### useReducer
`const [state, dispatch] = useReducer[reducer, initialState, init];` Esta es la forma inicial que tiene un useReducer
Si queremos usar este hook para verificar si un usuario inició sesión, podemos agregar:
```
interface AuthState { token: string | null };
type AuthAction = { type: ‘logout’} | { type: ‘login’ };
const initialState:AuthState = {token: null};
const authReducer = (state: AuthState, action: AuthAction):AuthState => {
	if(action.type == ‘logout’) {
		return { token: null }
	} else {
		return { token: ’123abc’ }
	}
}
export const Login = () => {
	const [state, dispatch] = useReducer(authReducer, initialState];
	useEffect(() => {
		dispatch({type: ‘logout’});
	}, []);	
	const login = () => {
		dispatch({type: ‘login’});
	}
	const logout = () => {
		dispatch({type: ‘logout’});
	}
}
```

El initialState nos dice el estado inicial del valor.
El reducer siempre debe retornar un dato del mismo tipo del initialState, para lo que podemos crear una interfaz con los datos necesarios, además, recibe dos parámetros, un state para el valor del estado y un action que modifica el valor del state.
También tenemos un dispatch, el cual es el método disparador de la acción para cambiar el state, están envueltos en una función, esa función se la podemos agregar a un botón o un elemento donde lo necesitemos.

### useEffect
Ejecuta el código en el momento en el que se carga el código en nuestra aplicación
```
useEffect(() => {
	console.log(“Hola”);
}, []}
```

### useNavigation
Sirve para recibir las props en la navegación desde un hook:
```
const navigator = useNavigation()
…
<Button title=‘Ir’ onPress={ () => navigator.navigate(‘Pagina’)} />
```

### useWindowDimensions
`const { width, height } = useWindowDimensions();` Permite obtener las dimensiones de la pantalla

### useColorScheme
`const colorScheme = useColorScheme();` Devuelve el tema que esta usando el dispositivo (light, dark…)

### useSafeAreaInsets
Ayuda a trabajar como un SafeAreaView pero más personalizado. Por ejemplo aquí nos ayuda a agregar un margen superior del tamaño necesario para que se vea el contenido. Pero solo en los celulares donde sea necesario.
```
const insets = useSafeAreaInsets();
return (
	<View style={.{ marginTop: insets.top }.}>
	…
)
```

### Hook personalizado
Para crear un archivo para almacenar un hook, hay que agregar ‘use’ al principio `useHook.tsx`.
En ese archivo hay que agregar la lógica relacionada al hook, como crear las variables y los métodos, suponiendo que tenemos ‘valor’ y ‘setValor’ en nuestro nuevo hook, hay que retornarlo:
```
export const useHook = () => { 
	const [valor, setValor] = useState(0); 
}
return { valor, setValor };
``` 
.
`const { valor, setValor } = useHook();` Importar ese hook en otro archivo para usarlo

#### Recibir parámetros
```
export const useHook = (valorInicial: number = 10) => { 
	const [valor, setValor] = useState(0); 
}
return { valor, setValor };
```
La función necesita un parámetro ‘valorInicial’ de tipo number el cual no es obligatorio, tomará el valor de 10 si no se le envía ningún parámetro
`const { valor, setValor } = useHook(5);` Se le envía un valor como parámetro

## Peticiones HTTP con Axios
`npm i axios` Instalar axios
`export const api = axios.create({ baseURL: ‘https://url.delapi/api});` Generar la conexión con la API para usarla más adelante
```
useEffect(() => {
api.get(‘/endpoint’)
	.then(res => {
		console.log(res.data);
	})
	.catch(console.error);
}, []);
```
Ejecutamos la llamada a la API en nuestro archivo, desde el useEffect e imprimimos la información necesaria
`api.get<String>(‘/endpoint’)` Podemos decirle el tipo de dato que esperamos, en este caso, un dato de tipo string, o podemos crear una interfaz personalizada

## Formularios
Podemos tener una variable para el formulario, con useState para guardar el valor cuando cambie.
La función onChange es la que se encarga de guardar el valor en la variable, heredando lo que ya se tenia, para no perder los datos.
```
const [formulario, setFormulario] = useState({
	email: ‘ejemplo@test.com’,
	password: ‘123’
});
const onChange = (value: string, campo:string) => {
	setFormulario({
		…formulario,
		[campo]: value
	});
}
…
<input 
	type=“text” 
	placeholder=“Email”
	value={ formulario.email }
	onChange = { ({ target }) => onChange(target.value, ‘email’) } />
```

## Navegación
### Stack Navigation
Funciona como una pila, en donde las pantallas se van poniendo una sobre otra, pero las pantallas siempre están activas.

*Instalaciones*
`npm install @react-navigation/native`
`npm install react-native-screens react-native-safe-area-context`
`npm install @react-navigation/native-stack`

*En App*
Hay que crear un NavigationContainer con un elemento Stack.Navigator, el cual es personalizado en este ejemplo:
```
const App = () => {
  return (
    <NavigationContainer>
        <StackNavigator />
    </NavigationContainer>
  )
}
```
Y en StackNavigator.tsx agregamos las pantallas que van a usarse
```
export const StackNavigator = () => {
  return (
    <Stack.Navigator>
      <Stack.Screen name="BoxObjectMrodel" component={BoxObjectModel} />
      <Stack.Screen name="Calculator" component={Calculator} />
      <Stack.Screen name="Counter" component={Counter} />
      <Stack.Screen name="Dimentions" component={Dimentions} />
      <Stack.Screen name="HelloWorld" component={HelloWorld} />
      <Stack.Screen name="Position" component={Position} />
    </Stack.Navigator>
  );
}
```

*Agregar un botón para ir a otra pantalla*
Hay que crear una interfaz para obtener las propiedades que pueden enviarse, además de tener las propiedades de la navegación, para poder navegar entre pantallas.
```
import type { NativeStackScreenProps } from '@react-navigation/native-stack';

interface Props extends NativeStackScreenProps<any, any> {}

const MenuStackNavigator = ({navigation}: Props) => {
  return (
    <View>
        <Button
            title='Ir a’
            onPress={() => {navigation.navigate(‘Pantalla’)}} />
    </View>
  )
}
```

*Métodos de navigation*
`const MiPagina = ({navigation}:any) => { <Button onPress={() => navigation.*método*}}`
Una vez que tenemos nuestro botón de ese modo, podemos agregar ciertos métodos:
`navigation.pop()` Sirve para volver al elemento anterior en el Stack
`navigation.popToTop()` Para ir al primer elemento del stack

*Propiedades del Stack.Navigator*
```
<Stack.Navigator *Propiedades*>
        <Stack.Screen name="Menu" component={MenuStackNavigator} /> 
</Stack.Navigator>
```
.
`initialRouteName=“Pagina2”` Define que pantalla será la primera en el stack
`screenOptions={{cardStyle: {`
`headerShown: false` Mostrar el título de la pantalla en donde se encuentra o no
`backgroundColor: ‘white’` Define el color que tendrá la vista (el contenido)
`}, headerStyle: {`
`elevation: 0` Elimina la línea divisoria entre el título y el contenido (android)
`shadowColor: ‘transparent’` Hace la línea divisoria de color transparente
`}}}` 

*Propiedades del Stack.Screen*
```
<Stack.Navigator>
        <Stack.Screen name="Menu" component={MenuStackNavigator} *Propiedades*/>
</Stack.Navigator>
```
.
`options={{title:”Titulo 1”}}` Para cambiar el título de la página

*Sobreescribir propiedades*
Para sobreescribir el título del componente podemos usar un hook para agregar las propiedades necesarias:
```
useEffect(() => {
	navigator.setOptions({ 
		title: ‘Nuevo titulo’
		headerBackTitle: ‘Atras’ //Para el texto iOS que aparece en la flecha de ir atrás
	})
}, [])
```

*Enviar argumentos entre pantallas*
En  el botón hay que agregar los argumentos después de poner a que pantalla queremos ir, puede ser una variable, un objeto, o algún elemento
```
<Button
    title='Ir a’
    onPress={() => {navigation.navigate(‘Pantalla’, argumentos)}} />
```
Para recibir los parámetros que enviamos podemos imprimirlo en consola:
`console.log(JSON.stringify(props, null, 3));`
Las props vienen en los parámetros de la función principal.
La mejor práctica para enviar parámetros se puede encontrar en la página del Navigator.

### Drawer Navigation
Es la pantalla que se desliza desde un lado de la pantalla, como un menu lateral.

*Instalaciones*
`npm install @react-navigation/drawer`

*Ejemplo básico*
El drawer va a generar un menú lateral con los elementos que le agreguemos en Drawer.Screen, aparece al arrastrar el dedo de izquierda a derecha en la pantalla.
```
import { createDrawerNavigator } from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

function MyDrawer() {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name="Feed" component={Feed} />
      <Drawer.Screen name="Article" component={Article} />
    </Drawer.Navigator>
  );
}
```

*Personalizar el drawer*
`<Drawer.Navigator`
`drawerPosition=‘right’` El drawer aparece del lado derecho
`drawerType=‘front’|’permanent’` Para elegir si queremos que por defecto el menú este oculto o no. Podemos usarlo para agregarlo dependiendo de si el celular esta en modo portrait o landscape agregando una condición ternaria: `drawerType={condición}`.
`drawerContent={(props) => <ContenidoInterno />}` Sirve para poder agregar contenido al drawer, como imágenes, vistas, etc. Hay que agregar los enlaces a otras secciones nuevamente con un TouchableOpacity/Button, etc
`>`.
`<Drawer.Screen options={{title’:Home’}} … />` Cambia el nombre que se verá en la pantalla

*Agregar icono de hamburguesa*
El ícono se coloca en las opciones de navegación y se agrega solo cuando inició la aplicación, por lo que podemos agregar un useEffect. Además hay que cambiar el tipo de las Props para poder tener acceso a las propiedades del drawer y de la navegación:
```
interface Props extends DrawerScreenProps<any, any>{};
…
useEffect(() => {
	navigation.setOptions({
		headerLeft: () => {
			<Button title=“Menu” onPress{() => navigation.toggleDrawer()} />
		}
	})
})
```

### BottomTab Navigation
Ofrece un menú inferior que funciona como una lista horizontal de enlaces que van hacia cada pantalla.

*Instalaciones*
`npm install @react-navigation/bottom-tabs`

*Ejemplo básico*
El Tab.Navigator contiene todas las pantallas que se van a colocar como Tabs
```
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

export const  MyTabs = () => {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}
```

*Personalizar las tabs*
`<Tab.Navigator`.
`sceneContainerStyle={{background: ‘white’}}` Pone el color del contenido de la tab en blanco
`screenOptions={({route}) => ({`
`tabBarActiveTintcolor: ‘red’,` Cambia el color del texto activo
`tabBarStyle: {`.
`borderTopColor: ‘red’,` Agrega un borde rojo a todo los tabs
`borderTopWidth: 0,` El ancho del borde es 0
`elevation: 0` Para que no se generen sombras (android)
`},`.
`tabBarLabelStyle: {fontSize: 14},` Cambia el tamaño de la fuente de las tabs
`tabBarIcon: ({color, focused, size}) => {` Cambia el icono del tab
```
let iconName: string = '';
      switch(route.name) {
          case 'MenuStackNavigator':
             iconName='MSN'
             break;
``` 
Podemos usar un switch para ver que texto usar

`return <Text style={{color}}>{iconName}</Text>` A todos los tabs les pone este texto como ícono y le pone color, el color que recibe como parámetro para que todos se vean igual
`}})}`.
`>`.
`<TabScreen … options={{ tabBaricon: <Icono props />}}/>` Agregar un ícono, podemos llamar a una etiqueta que reciba datos para cambiar los estilos

### Material Bottom Tab Navigation
Permite agregar estilos a la navegación que ya teníamos anteriormente en el menú inferior.
 *Instalación*
`npm install @react-navigation/material-bottom-tabs react-native-paper react-native-vector-icons`

*Ejemplo básico*
```
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';

const Tab = createMaterialBottomTabNavigator();

const MyTabs = () => {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}
```
Tenemos las mismas opciones de personalización que con los otros componentes.

### Material Top Tab Navigation
Es un menú superior que funciona del mismo modo que los componentes anteriores, al permitirte navegar entre diferentes pantallas.

*Instalaciones*
`npm install @react-navigation/material-top-tabs react-native-tab-view`
`npm install react-native-pager-view`

*Ejemplo básico*
```
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';

const Tab = createMaterialTopTabNavigator();

function MyTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}
```

Para personalizarlo tenemos las mismas opciones que con las otras navegaciones.

## Ejecutar código dependiendo de la plataforma
Podemos crear una función para Android, otra para iOS dentro de nuestra función principal y validar en qué plataforma se está trabajando para saber qué código hay que retornar:
```
const app = () => {
	const androidApp = () => {…}
	const iosApp = () => {…}
	return (Platform.OS === ‘ios’ ? iosApp() : androidApp();
}
```

### Agregar iconos
*Instalación*
`npm install --save react-native-vector-icons`
Y seguir la guía de instalación en https://github.com/oblador/react-native-vector-icons
Hay que instalar los tipos del paquete de iconos que elijamos:
`npm i -D @types/react-native-vector-icons`

*Agregar icono*
```
import Icon from 'react-native-vector-icons/FontAwesome';
const myIcon = <Icon name="rocket" size={30} color="#900" />;
```

## Animaciones
Creamos una función para que un elemento aparezca en pantalla, para eso necesitamos una referencia de su opacidad:
`const opacity = useRef(new Animated.Value(0)).current;`
Para hacer que un elemento aparezca, creamos la función:
```
const fadeIn = () => {
        Animated.timing(
            opacity, 
            {toValue: 1, duration: 1000, useNativeDriver: true}
        ).start();
    }
```
Y agregamos el elemento Animated.View para lo que queremos animar, junto a un botón que inicie la animación:
```
<Animated.View style={{
     backgroundColor: 'black',
     width: 150,
     height: 150,
     borderColor: 'white',
     borderWidth: 10,
     opacity: opacity
}} />
<Button
     title='Start fadeIn' 
     onPress={() => fadeIn()} />
```

## Verificar el estado de la app
Con el AppState de react-native podemos monitorear cuando nuestra aplicación esta activa, inactiva o si está en segundo plano.
```
useEffect(() => {
      AppState.addEventListener('change', state => {
        console.log(state);
      })
    }, [])
```

## Cambiar icono, nombre, splash screen de la app
### Cambiar el nombre
Hay que ir a android/app/src/main/res/strings.xml y ahi actualizar el texto de la aplicación que viene por defecto

### Cambiar ícono
Hay que crear un ícono (hay generadores de iconos en internet de donde podemos crear uno y descargarlo (descargar todas sus medidas disponibles).
Hay que tener images cuadradas y redondas. y almacenarlas en android/app/src/main/res/mipmap… cada una en su respectiva carpeta, y en cada una hay que tener una versión circular y una cuadrada del ícono.
En el AndroidManifest (android/app/src/main/AndroidManifest.xml) es en donde se definen los nombres de las imagenes que se toman por defecto.
```
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round”
```

### Splash creen
Se puede seguir el tutorial de este enlace: https://github.com/crazycodeboy/react-native-splash-screen
Hacer las instalaciones, modificaciones de los archivos nativos, crear los archivos launch_screen.xml y generar el diseño para el splash creen, después importar el paquete en la pantalla donde lo queremos mostrar y configurar el splash screen.

## Generar APK
Debe seguirse la guía de la documentación oficial: https://reactnative.dev/docs/signed-apk-android
 ## Subir a Google Play el app
Se sube desde: https://play.google.com/console/about/
Debe hacerse un pago y llenar los datos.

## Otros
`<Text style={styles.text}>Texto: {“\n”}Ejemplo</Text>` Para dar un salto de línea en el mismo Text
`const { width, height } = Dimensions.get('window');` Obtener el ancho y alto de la pantalla pero al girar el dispositivo, las medidas se mantienen cuando deberían cambiar, es mejor usar el hook ‘useWindowDimentions’
`<MiElemento opcionBool />` Si necesitamos enviarle props booleanas no es necesario inicializarla en true, el hecho de agregar la propiedad hace que se retorne un true

## Links
React Native con TypeScript: https://create-react-app.dev/docs/adding-typescript/
React Navigation: https://reactnavigation.org/docs/getting-started/
React Drawer Navigation: https://reactnavigation.org/docs/drawer-based-navigation/
Bottom Tab Navigator: https://reactnavigation.org/docs/bottom-tab-navigator/
Material Top Tab Navigator: https://reactnavigation.org/docs/material-top-tab-navigator/
React Native APIs: https://reactnative.dev/docs/accessibilityinfo
Colores en iOS: https://developer.apple.com/design/human-interface-guidelines/color Colores en Android: https://m2.material.io/design/color/color-usage.html
React Native con TypeScript: https://create-react-app.dev/docs/adding-typescript/
Iconos: https://github.com/oblador/react-native-vector-icons
Lista de iconos disponibles: https://ionic.io/ionicons
Carrusel: https://github.com/meliorence/react-native-snap-carousel
Gradientes: https://github.com/react-native-linear-gradient/react-native-linear-gradient
Analizar colores de imagenes: https://github.com/osamaqarem/react-native-image-colors
Temas: https://reactnavigation.org/docs/themes/
Permisos: https://www.npmjs.com/package/react-native-permissions
Extensiones: https://reactnative.dev/docs/app-extensions
Ejercicios: https://www.tutorialspoint.com/react_native/index.htm
Libro con ejercicios: https://books.goalkicker.com/ReactNativeBook/