{"id":26878207,"url":"https://github.com/urian121/react-native-guia-completa-componentes","last_synced_at":"2026-05-08T13:38:53.614Z","repository":{"id":282335516,"uuid":"948184616","full_name":"urian121/react-native-guia-completa-componentes","owner":"urian121","description":"Guía completa de componentes en React Native 📱. Aprende a usar y personalizar los principales componentes con ejemplos prácticos y buenas prácticas. Ideal para principiantes y desarrolladores avanzados. 🚀","archived":false,"fork":false,"pushed_at":"2025-05-10T19:28:54.000Z","size":177,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-10T20:26:24.688Z","etag":null,"topics":["frontend","guia-react-native","javascript","mobile-development","react","react-native","react-native-components","react-native-guide","react-native-tutorial","react-native-ui","reactnative","ui-components","ui-components-react-native"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/urian121.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-13T22:24:46.000Z","updated_at":"2025-05-10T19:28:57.000Z","dependencies_parsed_at":"2025-04-08T14:22:53.795Z","dependency_job_id":"01701fc1-05c4-4ae7-8767-0c79ad0fbad3","html_url":"https://github.com/urian121/react-native-guia-completa-componentes","commit_stats":null,"previous_names":["urian121/react-native-guia-completa-componentes"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/urian121/react-native-guia-completa-componentes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urian121%2Freact-native-guia-completa-componentes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urian121%2Freact-native-guia-completa-componentes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urian121%2Freact-native-guia-completa-componentes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urian121%2Freact-native-guia-completa-componentes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urian121","download_url":"https://codeload.github.com/urian121/react-native-guia-completa-componentes/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urian121%2Freact-native-guia-completa-componentes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32783087,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frontend","guia-react-native","javascript","mobile-development","react","react-native","react-native-components","react-native-guide","react-native-tutorial","react-native-ui","reactnative","ui-components","ui-components-react-native"],"created_at":"2025-03-31T12:19:57.494Z","updated_at":"2026-05-08T13:38:53.601Z","avatar_url":"https://github.com/urian121.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📖 Guía Completa de Componentes en React Native\n\nGuía completa de componentes en React Native 📱. Aprende a usar y personalizar los principales componentes con ejemplos prácticos y buenas prácticas. 🚀\n\n## 1️⃣ Instalación y Configuración\n\nSi aún no tienes un entorno de desarrollo configurado, puedes instalar **React Native CLI** o usar **Expo** (***recomendado por React***):\n\n### Instalación con Expo\n\n```bash\nnpx create-expo-app@latest my-app --template\ncd my-app\nnpx expo start\n```\n\n### Instalación con React Native CLI\n\n```bash\nnpx react-native init my-app\ncd my-app\nnpx react-native start\n```\n\n## 2️⃣ Primer Componente\n\nUn componente funcional básico en **React Native** se define así:\n\n```jsx\nimport React from 'react';\nimport { Text, View } from 'react-native';\n\nconst MiComponente = () =\u003e {\n  return (\n    \u003cView\u003e\n      \u003cText\u003e¡Hola, React Native!\u003c/Text\u003e\n    \u003c/View\u003e\n  );\n};\n\nexport default MiComponente;\n```\n\n📌 **Explicación:**\n- `\u003cView\u003e`: Similar a un `\u003cdiv\u003e` en HTML.\n- `\u003cText\u003e`: Se usa para mostrar texto.\n\n## 3️⃣ Componentes Básicos\n\n### 🟢 View (Contenedor)\n**`View`**: Es el componente más básico sobre el que heredan la mayoría de los demás componentes. Lo podríamos comparar como un `\u003cdiv\u003e` de HTML.\n\n```jsx\n\u003cView style={{ backgroundColor: 'lightgray', padding: 20, borderRadius: 5 }}\u003e\n  \u003cText\u003eEste es un contenedor\u003c/Text\u003e\n\u003c/View\u003e\n```\n\n### 📌 Importante  \n\u003e [!IMPORTANT]  \n\u003e En **React** y **React Native**, las dobles llaves (`{{ }}`) indican que estás pasando un **objeto** en **JSX**.  \n\u003e - La primera `{ }` permite escribir una expresión de **JavaScript** dentro de **JSX**.  \n\u003e - La segunda `{ }` contiene el objeto con los estilos en formato **clave-valor**.  \n\u003e\n\u003e 📌 Esto es necesario porque los estilos en React se definen como objetos de JavaScript en lugar de cadenas CSS.  \n\n\n#### Crear un contenedor fácilmente usando `View`\nEste código define un componente `Container` que usa `View` para envolver y aplicar estilos a sus hijos.\nEn `App`, el `Container` se reutiliza para mostrar un `Text` dentro de un fondo estilizado.\n\n```jsx\nimport React from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\n\nconst Container = ({ children }) =\u003e {\n  return \u003cView style={styles.container}\u003e{children}\u003c/View\u003e;\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 20,\n    backgroundColor: '#f5f5f5',\n  },\n});\n\nexport default function App() {\n  return (\n    \u003cContainer\u003e\n      \u003cText\u003eHola, esto está dentro del contenedor\u003c/Text\u003e\n    \u003c/Container\u003e\n  );\n}\n```\n\n### 🔤 Text (Texto)\n**`Text`**: Componente para mostrar textos.\n\n```jsx\n\u003cText style={{ fontSize: 20, fontWeight: 'bold', color: '#333' }}\u003e\n  Texto en React Native\n\u003c/Text\u003e\n```\n\n### 🔘 Button (Botón)\n**`Button`**: Sirve para crear botones interactivos básicos con una apariencia estándar según la plataforma (iOS o Android).\n\n```jsx\nimport { Button } from 'react-native';\n\n\u003cButton \n  title=\"Presionar\" \n  onPress={() =\u003e alert('¡Clic!')} \n  color=\"#841584\" \n/\u003e\n```\n\n### 🎛️ TextInput (Caja de Texto)\n**`TextInput`**: Componente que proporciona un espacio al usuario para que pueda ingresar texto por medio del teclado de su dispositivo.\n\n```jsx\nimport React, { useState } from 'react';\nimport { TextInput } from 'react-native';\n\nconst InputExample = () =\u003e {\n  const [texto, setTexto] = useState('');\n  \n  return (\n    \u003cTextInput\n      placeholder=\"Escribe aquí\"\n      value={texto}\n      onChangeText={setTexto}\n      style={{ \n        borderWidth: 1, \n        borderColor: '#ccc', \n        borderRadius: 5,\n        padding: 10 \n      }}\n    /\u003e\n  );\n};\n```\n\n### 📸 Image (Imagen)\n**`Image`**: Componente que sirve para mostrar imágenes\n\n```jsx\nimport { StyleSheet, Image, View } from 'react-native';\nimport imgLogo from './assets/snack-icon.png'; // Imagen importada como módulo\nconst image = require('./assets/snack-icon.png'); // Imagen como variable con require\n\nexport default function App() {\n  return (\n    \u003cView style={styles.container}\u003e\n      {/* Imagen desde URL */}\n      \u003cImage \n        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} \n        style={styles.image} \n      /\u003e\n\n      {/* Imagen local con require */}\n      \u003cImage \n        source={require('./assets/snack-icon.png')} \n        style={styles.image} \n      /\u003e\n\n      {/* Imagen desde variable */}\n      \u003cImage \n        source={image} \n        style={styles.image} \n      /\u003e\n\n      {/* Imagen importada */}\n      \u003cImage \n        source={imgLogo} \n        style={styles.image} \n      /\u003e\n    \u003c/View\u003e\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',   // Centrado vertical\n    alignItems: 'center',       // Centrado horizontal\n    backgroundColor: '#ecf0f1',\n    padding: 8,\n  },\n  image: {\n    width: 100,\n    height: 100,\n    marginBottom: 10,           // Espacio entre imágenes\n  },\n});\n```\n### 📱 Componente SafeAreaView\nSe usa para asegurarse de que el contenido de la pantalla no se superponga con áreas seguras del dispositivo, como el **`notch`** en iPhones o la barra de navegación en **`Android`**.\n\n#### Cómo funciona 🤔\n\n- `SafeAreaView` ajusta automáticamente su padding para evitar que el contenido quede oculto detrás de áreas no seguras.\nFunciona mejor en **iOS**, pero en **Android** no tiene efecto a menos que uses SafeAreaProvider de la librería `react-native-safe-area-context`.\n\n```jsx\nimport React from 'react';\nimport { SafeAreaView, Text, StyleSheet } from 'react-native';\n\nexport default function App() {\n  return (\n    \u003cSafeAreaView style={styles.container}\u003e\n      \u003cText\u003eHola, esto está dentro de SafeAreaView\u003c/Text\u003e\n    \u003c/SafeAreaView\u003e\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: '#f5f5f5',\n  },\n});\n```\n\n#### 📝 Mejor soporte en Android\nEn **Android**, para un mejor comportamiento, usa `SafeAreaProvider` de `react-native-safe-area-context`:\n\n1. Instala la librería\n`npm install react-native-safe-area-context`\n\n2. Implementación con SafeAreaProvider\n\n```jsx\nimport React from 'react';\nimport { SafeAreaView, Text, StyleSheet } from 'react-native';\nimport { SafeAreaProvider } from 'react-native-safe-area-context';\n\nexport default function App() {\n  return (\n    \u003cSafeAreaProvider\u003e\n      \u003cSafeAreaView style={styles.container}\u003e\n        \u003cText\u003eContenido seguro en iOS y Android\u003c/Text\u003e\n      \u003c/SafeAreaView\u003e\n    \u003c/SafeAreaProvider\u003e\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: '#f5f5f5',\n  },\n});\n```\n✅ Con esta configuración, el `SafeAreaView` funciona bien en **iOS** y **Android**.\n\n### 📜 ScrollView (Vista Desplazable)\n**`ScrollView`**: Componente que permite establecer un contenedor en el que se podrán almacenar varios componentes que se pueden ir desplazando en la pantalla.\n\n```jsx\nimport React, { useState } from 'react';\nimport { ScrollView, View, Text, StyleSheet } from 'react-native';\n\nconst ScrollViewExample = () =\u003e {\n  return (\n    \u003cScrollView style={{ flex: 1 }}\u003e\n      {/* Contenido que puede desplazarse verticalmente */}\n      \u003cView style={{ height: 200, backgroundColor: 'pink', margin: 10 }}\u003e\n        \u003cText\u003eSección 1\u003c/Text\u003e\n      \u003c/View\u003e\n      \u003cView style={{ height: 200, backgroundColor: 'skyblue', margin: 10 }}\u003e\n        \u003cText\u003eSección 2\u003c/Text\u003e\n      \u003c/View\u003e\n      \u003cView style={{ height: 200, backgroundColor: 'lightgreen', margin: 10 }}\u003e\n        \u003cText\u003eSección 3\u003c/Text\u003e\n      \u003c/View\u003e\n    \u003c/ScrollView\u003e\n  );\n};\n\n// ScrollView horizontal\nconst HorizontalScrollExample = () =\u003e {\n  return (\n    \u003cScrollView \n      horizontal={true} \n      showsHorizontalScrollIndicator={false}\n      style={{ height: 200 }}\n    \u003e\n      \u003cView style={{ width: 150, height: 150, backgroundColor: 'red', margin: 10 }} /\u003e\n      \u003cView style={{ width: 150, height: 150, backgroundColor: 'blue', margin: 10 }} /\u003e\n      \u003cView style={{ width: 150, height: 150, backgroundColor: 'green', margin: 10 }} /\u003e\n    \u003c/ScrollView\u003e\n  );\n};\n```\n\n### 🔄 ActivityIndicator (Indicador de Carga)\n**`ActivityIndicator`**: Muestra un indicador de carga circular animado.\nSe utiliza para indicar a los usuarios que una operación está en proceso, como cuando se están cargando datos de una `API`, procesando información o realizando cualquier tarea que requiera tiempo.\n\n```jsx\nimport React, { useState } from 'react';\nimport { ActivityIndicator, View } from 'react-native';\n\nconst LoadingIndicator = () =\u003e {\n  return (\n    \u003cView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}\u003e\n      \u003cActivityIndicator size=\"large\" color=\"#0000ff\" /\u003e\n    \u003c/View\u003e\n  );\n};\n```\n\n### 📱 TouchableOpacity (Área Táctil)\n**`TouchableOpacity`**: Crea áreas táctiles que responden al toque del usuario con un efecto de opacidad. \nCuando el usuario presiona el elemento, este se vuelve ligeramente transparente (reduce su opacidad) para proporcionar retroalimentación visual.\n\n```jsx\nimport React, { useState } from 'react';\nimport { TouchableOpacity, Text } from 'react-native';\n\nconst TouchableExample = () =\u003e {\n  return (\n    \u003cTouchableOpacity \n      style={{ \n        backgroundColor: '#2196F3', \n        padding: 10, \n        borderRadius: 5,\n        alignItems: 'center' \n      }}\n      onPress={() =\u003e alert('Tocado!')}\n    \u003e\n      \u003cText style={{ color: 'white' }}\u003eBotón Personalizado\u003c/Text\u003e\n    \u003c/TouchableOpacity\u003e\n  );\n};\n```\n\n## 4️⃣ Componentes con Estado (`useState`)\nPara manejar datos dentro de un componente usamos `useState`:\n\n```jsx\nimport React, { useState } from 'react';\nimport { View, Text, Button, StyleSheet } from 'react-native';\n\nconst Contador = () =\u003e {\n  const [contador, setContador] = useState(0);\n  \n  return (\n    \u003cView style={styles.container}\u003e\n      \u003cText style={styles.contador}\u003eContador: {contador}\u003c/Text\u003e\n      \u003cView style={styles.buttonRow}\u003e\n        \u003cButton title=\"Incrementar\" onPress={() =\u003e setContador(contador + 1)} /\u003e\n        \u003cButton title=\"Decrementar\" onPress={() =\u003e setContador(contador - 1)} /\u003e\n      \u003c/View\u003e\n      \u003cButton title=\"Reiniciar\" onPress={() =\u003e setContador(0)} /\u003e\n    \u003c/View\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    padding: 20,\n    alignItems: 'center',\n  },\n  contador: {\n    fontSize: 24,\n    marginBottom: 20,\n  },\n  buttonRow: {\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n    width: '100%',\n    marginBottom: 10,\n  },\n});\n\nexport default Contador;\n```\n\n📌 **Explicación:**\n- `useState(0)`: Crea una variable de estado (contador) con valor inicial `0`.\n- `setContador(contador + 1)`: Actualiza el estado al hacer clic.\n\n## 5️⃣ Estilos en React Native\nSe pueden definir estilos de dos maneras:\n\n### 1️⃣ Estilos en línea\n\n```jsx\n\u003cText style={{ color: 'blue', fontSize: 20, fontWeight: 'bold' }}\u003e\n  Texto Azul\n\u003c/Text\u003e\n```\n\n### 2️⃣ Estilos con StyleSheet (Recomendado)\n**`StyleSheet`**: Componente en el que añadiremos los estilos del componente.\n\n```jsx\nimport React, { useState } from 'react';\nimport { StyleSheet, View, Text } from 'react-native';\n\nconst MiComponente = () =\u003e {\n  return (\n    \u003cView style={styles.container}\u003e\n      \u003cText style={styles.titulo}\u003eTítulo Principal\u003c/Text\u003e\n      \u003cText style={styles.subtitulo}\u003eSubtítulo\u003c/Text\u003e\n    \u003c/View\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    padding: 20,\n    backgroundColor: '#f5f5f5',\n  },\n  titulo: { \n    color: 'red', \n    fontSize: 24,\n    fontWeight: 'bold',\n    marginBottom: 10,\n  },\n  subtitulo: {\n    color: '#333',\n    fontSize: 18,\n  }\n});\n\nexport default MiComponente;\n```\n\n### 3️⃣ Combinando estilos\n\n```jsx\n\u003cText style={[styles.texto, { color: 'green' }]}\u003e\n  Este texto combina estilos\n\u003c/Text\u003e\n```\n\n## 6️⃣ Diseño con Flexbox\n**React Native** utiliza Flexbox para el diseño:\n\n```jsx\nimport { View, StyleSheet } from 'react-native';\n\nexport default FlexboxExample = () =\u003e {\n  return (\n    \u003cView style={styles.container}\u003e\n      \u003cView style={styles.box1} /\u003e\n      \u003cView style={styles.box2} /\u003e\n      \u003cView style={styles.box3} /\u003e\n    \u003c/View\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    flexDirection: 'row', // 'column', 'row', 'column-reverse', 'row-reverse'\n    justifyContent: 'space-between', // 'flex-start', 'flex-end', 'center', 'space-around'\n    alignItems: 'center', // 'flex-start', 'flex-end', 'stretch'\n    padding: 20,\n  },\n  box1: { width: 50, height: 50, backgroundColor: 'red' },\n  box2: { width: 50, height: 50, backgroundColor: 'green' },\n  box3: { width: 50, height: 50, backgroundColor: 'blue' },\n});\n```\n\n## 7️⃣ Listas y Scroll\n\n### FlatList (Para listas largas)\nRenderiza listas de datos extensas de forma eficiente, cargando solo los elementos visibles en pantalla. Es ideal para mostrar grandes colecciones de datos con buen rendimiento.\n\n```jsx\nimport React, { useState } from 'react';\nimport { FlatList, Text, View, StyleSheet } from 'react-native';\n\nconst datos = [\n  { id: '1', nombre: 'Juan' },\n  { id: '2', nombre: 'Ana' },\n  { id: '3', nombre: 'Carlos' },\n  { id: '4', nombre: 'María' },\n  // ... más datos\n];\n\nconst Lista = () =\u003e (\n  \u003cFlatList\n    data={datos}\n    keyExtractor={(item) =\u003e item.id}\n    renderItem={({ item }) =\u003e (\n      \u003cView style={styles.item}\u003e\n        \u003cText style={styles.nombre}\u003e{item.nombre}\u003c/Text\u003e\n      \u003c/View\u003e\n    )}\n    ItemSeparatorComponent={() =\u003e \u003cView style={styles.separator} /\u003e}\n  /\u003e\n);\n\nconst styles = StyleSheet.create({\n  item: {\n    padding: 15,\n    backgroundColor: 'white',\n  },\n  nombre: {\n    fontSize: 16,\n  },\n  separator: {\n    height: 1,\n    backgroundColor: '#eeeeee',\n  },\n});\n\nexport default Lista;\n```\n\n### 📜 SectionList (Para listas con secciones)\nMuestra datos organizados en secciones con encabezados. Es similar a FlatList pero permite agrupar elementos relacionados bajo títulos de sección, ideal para datos categorizados como contactos por inicial, productos por categoría o ajustes agrupados por función.\n\n```jsx\nimport React, { useState } from 'react';\nimport { SectionList, Text, View, StyleSheet } from 'react-native';\n\nconst datos = [\n  {\n    title: 'Frutas',\n    data: ['Manzana', 'Banana', 'Naranja'],\n  },\n  {\n    title: 'Verduras',\n    data: ['Zanahoria', 'Brócoli', 'Espinaca'],\n  },\n];\n\nconst SectionListExample = () =\u003e (\n  \u003cSectionList\n    sections={datos}\n    keyExtractor={(item, index) =\u003e item + index}\n    renderItem={({ item }) =\u003e (\n      \u003cView style={styles.item}\u003e\n        \u003cText style={styles.itemText}\u003e{item}\u003c/Text\u003e\n      \u003c/View\u003e\n    )}\n    renderSectionHeader={({ section: { title } }) =\u003e (\n      \u003cView style={styles.sectionHeader}\u003e\n        \u003cText style={styles.sectionTitle}\u003e{title}\u003c/Text\u003e\n      \u003c/View\u003e\n    )}\n  /\u003e\n);\n\nconst styles = StyleSheet.create({\n  item: {\n    padding: 10,\n    backgroundColor: 'white',\n  },\n  itemText: {\n    fontSize: 16,\n  },\n  sectionHeader: {\n    padding: 10,\n    backgroundColor: '#f0f0f0',\n  },\n  sectionTitle: {\n    fontSize: 18,\n    fontWeight: 'bold',\n  },\n});\n```\n\n## 8️⃣ Uso de API con `fetch`\nPara obtener datos de una API usamos `fetch`:\n\n```jsx\nimport React, { useEffect, useState } from 'react';\nimport { View, Text, FlatList, StyleSheet, ActivityIndicator } from 'react-native';\n\nconst ApiExample = () =\u003e {\n  const [data, setData] = useState([]);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n\n  useEffect(() =\u003e {\n    const fetchData = async () =\u003e {\n      try {\n        const response = await fetch('https://jsonplaceholder.typicode.com/users');\n        if (!response.ok) {\n          throw new Error('La respuesta de la red no fue satisfactoria');\n        }\n        const json = await response.json();\n        setData(json);\n      } catch (err) {\n        setError(err.message);\n      } finally {\n        setLoading(false);\n      }\n    };\n\n    fetchData();\n  }, []);\n\n  if (loading) {\n    return (\n      \u003cView style={styles.centered}\u003e\n        \u003cActivityIndicator size=\"large\" color=\"#0000ff\" /\u003e\n      \u003c/View\u003e\n    );\n  }\n\n  if (error) {\n    return (\n      \u003cView style={styles.centered}\u003e\n        \u003cText style={styles.error}\u003eError: {error}\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n\n  return (\n    \u003cFlatList\n      data={data}\n      keyExtractor={(item) =\u003e item.id.toString()}\n      renderItem={({ item }) =\u003e (\n        \u003cView style={styles.userItem}\u003e\n          \u003cText style={styles.userName}\u003e{item.name}\u003c/Text\u003e\n          \u003cText style={styles.userEmail}\u003e{item.email}\u003c/Text\u003e\n        \u003c/View\u003e\n      )}\n    /\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  centered: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n  error: {\n    color: 'red',\n    fontSize: 18,\n  },\n  userItem: {\n    padding: 15,\n    borderBottomWidth: 1,\n    borderBottomColor: '#eee',\n  },\n  userName: {\n    fontSize: 18,\n    fontWeight: 'bold',\n  },\n  userEmail: {\n    fontSize: 14,\n    color: '#666',\n  },\n});\n\nexport default ApiExample;\n```\n\n## 9️⃣ Navegación entre Pantallas\nPara la navegación, instala `React Navigation`:\n\n```bash\nnpm install @react-navigation/native\nnpx expo install react-native-screens react-native-safe-area-context\nnpm install @react-navigation/native-stack\n```\n\n### Ejemplo de Navegación Básica\n\n```jsx\nimport React from 'react';\nimport { NavigationContainer } from '@react-navigation/native';\nimport { createNativeStackNavigator } from '@react-navigation/native-stack';\nimport { Button, Text, View } from 'react-native';\n\n// Pantalla de Inicio\nconst HomeScreen = ({ navigation }) =\u003e {\n  return (\n    \u003cView style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}\u003e\n      \u003cText style={{ fontSize: 24, marginBottom: 20 }}\u003ePantalla de Inicio\u003c/Text\u003e\n      \u003cButton\n        title=\"Ir a Detalles\"\n        onPress={() =\u003e navigation.navigate('Details', { itemId: 86, title: 'Mi Título' })}\n      /\u003e\n    \u003c/View\u003e\n  );\n};\n\n// Pantalla de Detalles\nconst DetailsScreen = ({ route, navigation }) =\u003e {\n  const { itemId, title } = route.params;\n  \n  return (\n    \u003cView style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}\u003e\n      \u003cText style={{ fontSize: 24, marginBottom: 10 }}\u003ePantalla de Detalles\u003c/Text\u003e\n      \u003cText\u003eitemId: {itemId}\u003c/Text\u003e\n      \u003cText\u003etitle: {title}\u003c/Text\u003e\n      \u003cButton title=\"Regresar\" onPress={() =\u003e navigation.goBack()} /\u003e\n    \u003c/View\u003e\n  );\n};\n\nconst Stack = createNativeStackNavigator();\n\nconst App = () =\u003e {\n  return (\n    \u003cNavigationContainer\u003e\n      \u003cStack.Navigator initialRouteName=\"Home\"\u003e\n        \u003cStack.Screen \n          name=\"Home\" \n          component={HomeScreen} \n          options={{ title: 'Inicio' }}\n        /\u003e\n        \u003cStack.Screen \n          name=\"Details\" \n          component={DetailsScreen}\n          options={({ route }) =\u003e ({ title: route.params.title })}\n        /\u003e\n      \u003c/Stack.Navigator\u003e\n    \u003c/NavigationContainer\u003e\n  );\n};\n\nexport default App;\n```\n\n## 🔟 Hooks Comunes\n\n### `useEffect` (Efectos Secundarios)\n**`useEffect`** es un hook de efectos secundarios que permite ejecutar código en diferentes momentos del ciclo de vida de un componente.\nSe usa comúnmente para **cargar datos, suscribirse a eventos, manipular el DOM, o ejecutar lógica después de renderizar**.\n\n```jsx\nimport React, { useState, useEffect } from 'react';\nimport { Text, View } from 'react-native';\n\nconst Timer = () =\u003e {\n  const [seconds, setSeconds] = useState(0);\n\n  useEffect(() =\u003e {\n    const interval = setInterval(() =\u003e {\n      setSeconds(prevSeconds =\u003e prevSeconds + 1);\n    }, 1000);\n    \n    // Función de limpieza\n    return () =\u003e clearInterval(interval);\n  }, []); // Array vacío = ejecutar solo al montar\n\n  return (\n    \u003cView\u003e\n      \u003cText\u003eSegundos: {seconds}\u003c/Text\u003e\n    \u003c/View\u003e\n  );\n};\n```\n\n### `useContext` (Contexto Global)\n**`useContext`**: permite acceder a un contexto global en cualquier parte de la aplicación sin necesidad de pasar `props` manualmente.\nEs útil para manejar estados globales como autenticación, temas, idiomas, etc.\n\n```jsx\nimport React, { createContext, useContext, useState } from 'react';\nimport { View, Text, Button } from 'react-native';\n\n// Crear el contexto\nconst TemaContext = createContext();\n\n// Proveedor de contexto\nconst TemaProvider = ({ children }) =\u003e {\n  const [tema, setTema] = useState('claro');\n  \n  const cambiarTema = () =\u003e {\n    setTema(temaActual =\u003e temaActual === 'claro' ? 'oscuro' : 'claro');\n  };\n  \n  return (\n    \u003cTemaContext.Provider value={{ tema, cambiarTema }}\u003e\n      {children}\n    \u003c/TemaContext.Provider\u003e\n  );\n};\n\n// Componente que consume el contexto\nconst ComponenteTematizado = () =\u003e {\n  const { tema, cambiarTema } = useContext(TemaContext);\n  \n  return (\n    \u003cView style={{ \n      backgroundColor: tema === 'claro' ? '#fff' : '#333',\n      padding: 20 \n    }}\u003e\n      \u003cText style={{ \n        color: tema === 'claro' ? '#000' : '#fff' \n      }}\u003e\n        Tema actual: {tema}\n      \u003c/Text\u003e\n      \u003cButton title=\"Cambiar Tema\" onPress={cambiarTema} /\u003e\n    \u003c/View\u003e\n  );\n};\n\n// Uso en la app\nconst App = () =\u003e {\n  return (\n    \u003cTemaProvider\u003e\n      \u003cComponenteTematizado /\u003e\n    \u003c/TemaProvider\u003e\n  );\n};\n```\n\n## 1️⃣1️⃣ Manejo de Formularios\n\n```jsx\nimport React, { useState } from 'react';\nimport { View, TextInput, Button, Text, StyleSheet, Alert } from 'react-native';\n\nconst FormularioExample = () =\u003e {\n  const [formState, setFormState] = useState({\n    nombre: '',\n    email: '',\n    password: ''\n  });\n  \n  const [errors, setErrors] = useState({});\n  \n  const handleChange = (field, value) =\u003e {\n    setFormState({\n      ...formState,\n      [field]: value\n    });\n  };\n  \n  const validarFormulario = () =\u003e {\n    let tempErrors = {};\n    \n    if (!formState.nombre) tempErrors.nombre = \"El nombre es obligatorio\";\n    if (!formState.email) tempErrors.email = \"El email es obligatorio\";\n    else if (!/\\S+@\\S+\\.\\S+/.test(formState.email)) {\n      tempErrors.email = \"Email inválido\";\n    }\n    if (!formState.password) tempErrors.password = \"La contraseña es obligatoria\";\n    else if (formState.password.length \u003c 6) {\n      tempErrors.password = \"La contraseña debe tener al menos 6 caracteres\";\n    }\n    \n    setErrors(tempErrors);\n    return Object.keys(tempErrors).length === 0;\n  };\n  \n  const handleSubmit = () =\u003e {\n    if (validarFormulario()) {\n      // Aquí enviarías los datos al servidor\n      Alert.alert(\"Éxito\", \"Formulario enviado correctamente\");\n      console.log(\"Datos del formulario:\", formState);\n    }\n  };\n  \n  return (\n    \u003cView style={styles.form}\u003e\n      \u003cText style={styles.label}\u003eNombre:\u003c/Text\u003e\n      \u003cTextInput\n        style={[styles.input, errors.nombre \u0026\u0026 styles.errorInput]}\n        value={formState.nombre}\n        onChangeText={(text) =\u003e handleChange('nombre', text)}\n        placeholder=\"Escribe tu nombre\"\n      /\u003e\n      {errors.nombre \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.nombre}\u003c/Text\u003e}\n      \n      \u003cText style={styles.label}\u003eEmail:\u003c/Text\u003e\n      \u003cTextInput\n        style={[styles.input, errors.email \u0026\u0026 styles.errorInput]}\n        value={formState.email}\n        onChangeText={(text) =\u003e handleChange('email', text)}\n        placeholder=\"tu@email.com\"\n        keyboardType=\"email-address\"\n        autoCapitalize=\"none\"\n      /\u003e\n      {errors.email \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.email}\u003c/Text\u003e}\n      \n      \u003cText style={styles.label}\u003eContraseña:\u003c/Text\u003e\n      \u003cTextInput\n        style={[styles.input, errors.password \u0026\u0026 styles.errorInput]}\n        value={formState.password}\n        onChangeText={(text) =\u003e handleChange('password', text)}\n        placeholder=\"********\"\n        secureTextEntry\n      /\u003e\n      {errors.password \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.password}\u003c/Text\u003e}\n      \n      \u003cButton title=\"Enviar\" onPress={handleSubmit} /\u003e\n    \u003c/View\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  form: {\n    padding: 20,\n  },\n  label: {\n    fontSize: 16,\n    marginBottom: 5,\n    fontWeight: 'bold',\n  },\n  input: {\n    borderWidth: 1,\n    borderColor: '#ddd',\n    padding: 10,\n    borderRadius: 5,\n    marginBottom: 15,\n  },\n  errorInput: {\n    borderColor: 'red',\n  },\n  errorText: {\n    color: 'red',\n    fontSize: 12,\n    marginTop: -10,\n    marginBottom: 10,\n  }\n});\n\nexport default FormularioExample;\n```\n\n### 📋 Formulario con `react-hook-form` en React Native\nEsta librería facilita mucho la validación y gestión de formularios.\n\n```jsx\nimport React from 'react';\nimport { View, Text, TextInput, Button, StyleSheet, ScrollView, Alert } from 'react-native';\nimport { useForm, Controller } from 'react-hook-form';\n\nconst FormularioEjemplo = () =\u003e {\n  const { control, handleSubmit, formState: { errors }, reset } = useForm({\n    defaultValues: {\n      nombre: '',\n      correo: '',\n      telefono: '',\n      edad: '',\n      mensaje: ''\n    }\n  });\n\n  const onSubmit = (data) =\u003e {\n    // Aquí procesarías el envío del formulario\n    console.log('Datos del formulario:', data);\n    \n    // Mostrar los datos enviados\n    Alert.alert(\n      'Formulario Enviado',\n      `Nombre: ${data.nombre}\\nCorreo: ${data.correo}\\nTeléfono: ${data.telefono}\\nEdad: ${data.edad}\\nMensaje: ${data.mensaje}`,\n      [{ text: 'OK', onPress: () =\u003e reset() }]\n    );\n  };\n\n  return (\n    \u003cScrollView contentContainerStyle={styles.container}\u003e\n      \u003cText style={styles.title}\u003eFormulario de Contacto\u003c/Text\u003e\n      \n      {/* Control de Nombre */}\n      \u003cText style={styles.label}\u003eNombre:\u003c/Text\u003e\n      \u003cController\n        control={control}\n        rules={{\n          required: 'Este campo es obligatorio',\n          minLength: {\n            value: 3,\n            message: 'El nombre debe tener al menos 3 caracteres'\n          }\n        }}\n        render={({ field: { onChange, onBlur, value } }) =\u003e (\n          \u003cTextInput\n            style={styles.input}\n            onBlur={onBlur}\n            onChangeText={onChange}\n            value={value}\n            placeholder=\"Ingresa tu nombre completo\"\n          /\u003e\n        )}\n        name=\"nombre\"\n      /\u003e\n      {errors.nombre \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.nombre.message}\u003c/Text\u003e}\n      \n      {/* Control de Correo */}\n      \u003cText style={styles.label}\u003eCorreo electrónico:\u003c/Text\u003e\n      \u003cController\n        control={control}\n        rules={{\n          required: 'El correo es obligatorio',\n          pattern: {\n            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$/i,\n            message: 'El formato del correo no es válido'\n          }\n        }}\n        render={({ field: { onChange, onBlur, value } }) =\u003e (\n          \u003cTextInput\n            style={styles.input}\n            onBlur={onBlur}\n            onChangeText={onChange}\n            value={value}\n            placeholder=\"ejemplo@correo.com\"\n            keyboardType=\"email-address\"\n            autoCapitalize=\"none\"\n          /\u003e\n        )}\n        name=\"correo\"\n      /\u003e\n      {errors.correo \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.correo.message}\u003c/Text\u003e}\n      \n      {/* Control de Teléfono */}\n      \u003cText style={styles.label}\u003eTeléfono:\u003c/Text\u003e\n      \u003cController\n        control={control}\n        rules={{\n          pattern: {\n            value: /^[0-9]{10}$/,\n            message: 'Ingresa un número de 10 dígitos'\n          }\n        }}\n        render={({ field: { onChange, onBlur, value } }) =\u003e (\n          \u003cTextInput\n            style={styles.input}\n            onBlur={onBlur}\n            onChangeText={onChange}\n            value={value}\n            placeholder=\"Teléfono (10 dígitos)\"\n            keyboardType=\"phone-pad\"\n          /\u003e\n        )}\n        name=\"telefono\"\n      /\u003e\n      {errors.telefono \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.telefono.message}\u003c/Text\u003e}\n      \n      {/* Control de Edad */}\n      \u003cText style={styles.label}\u003eEdad:\u003c/Text\u003e\n      \u003cController\n        control={control}\n        rules={{\n          pattern: {\n            value: /^[0-9]+$/,\n            message: 'Ingresa solo números'\n          },\n          validate: value =\u003e parseInt(value) \u003e= 18 || 'Debes ser mayor de edad'\n        }}\n        render={({ field: { onChange, onBlur, value } }) =\u003e (\n          \u003cTextInput\n            style={styles.input}\n            onBlur={onBlur}\n            onChangeText={onChange}\n            value={value}\n            placeholder=\"Edad\"\n            keyboardType=\"numeric\"\n          /\u003e\n        )}\n        name=\"edad\"\n      /\u003e\n      {errors.edad \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.edad.message}\u003c/Text\u003e}\n      \n      {/* Control de Mensaje */}\n      \u003cText style={styles.label}\u003eMensaje:\u003c/Text\u003e\n      \u003cController\n        control={control}\n        rules={{\n          maxLength: {\n            value: 500,\n            message: 'El mensaje no puede exceder los 500 caracteres'\n          }\n        }}\n        render={({ field: { onChange, onBlur, value } }) =\u003e (\n          \u003cTextInput\n            style={[styles.input, styles.textArea]}\n            onBlur={onBlur}\n            onChangeText={onChange}\n            value={value}\n            placeholder=\"Escribe tu mensaje aquí\"\n            multiline\n            numberOfLines={4}\n          /\u003e\n        )}\n        name=\"mensaje\"\n      /\u003e\n      {errors.mensaje \u0026\u0026 \u003cText style={styles.errorText}\u003e{errors.mensaje.message}\u003c/Text\u003e}\n      \n      \u003cButton\n        title=\"Enviar Formulario\"\n        onPress={handleSubmit(onSubmit)}\n        color=\"#4CAF50\"\n      /\u003e\n    \u003c/ScrollView\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    padding: 20,\n    backgroundColor: '#f5f5f5',\n  },\n  title: {\n    fontSize: 24,\n    fontWeight: 'bold',\n    marginBottom: 20,\n    textAlign: 'center',\n  },\n  label: {\n    fontSize: 16,\n    marginBottom: 5,\n    fontWeight: '500',\n  },\n  input: {\n    borderWidth: 1,\n    borderColor: '#ddd',\n    borderRadius: 4,\n    padding: 10,\n    marginBottom: 12,\n    backgroundColor: '#fff',\n  },\n  textArea: {\n    height: 100,\n    textAlignVertical: 'top',\n  },\n  errorText: {\n    color: 'red',\n    fontSize: 12,\n    marginBottom: 10,\n    marginTop: -8,\n  },\n});\n\nexport default FormularioEjemplo;\n```\n\nEste formulario en **React Native** usa `react-hook-form` para gestionar y validar los campos de entrada.  \n`Controller` maneja cada `TextInput`, aplicando reglas como requerimientos, validaciones de formato y longitud.  \nLos errores se muestran dinámicamente debajo de cada campo.  \nAl enviarlo, los datos se muestran en una alerta y el formulario se reinicia con `reset()`.  \nTambién utiliza `ScrollView` para evitar problemas de desplazamiento en pantallas pequeñas. \n\n\n## 1️⃣2️⃣ Mejores Prácticas\n\n### Separar Lógica y Presentación\n\n```jsx\n// Component/UserProfile/index.js (Componente contenedor - lógica)\nimport React, { useState, useEffect } from 'react';\nimport UserProfileView from './UserProfileView';\n\nconst UserProfile = ({ userId }) =\u003e {\n  const [userData, setUserData] = useState(null);\n  const [loading, setLoading] = useState(true);\n  \n  useEffect(() =\u003e {\n    // Obtener datos del usuario\n    fetch(`https://api.example.com/users/${userId}`)\n      .then(response =\u003e response.json())\n      .then(data =\u003e {\n        setUserData(data);\n        setLoading(false);\n      });\n  }, [userId]);\n  \n  const handleUpdateName = (newName) =\u003e {\n    // Lógica para actualizar nombre\n  };\n  \n  return (\n    \u003cUserProfileView\n      userData={userData}\n      loading={loading}\n      onUpdateName={handleUpdateName}\n    /\u003e\n  );\n};\n\n// Component/UserProfile/UserProfileView.js (Componente de presentación)\nimport React from 'react';\nimport { View, Text, ActivityIndicator, Button, TextInput } from 'react-native';\n\nconst UserProfileView = ({ userData, loading, onUpdateName }) =\u003e {\n  if (loading) {\n    return \u003cActivityIndicator size=\"large\" /\u003e;\n  }\n  \n  return (\n    \u003cView\u003e\n      \u003cText\u003eNombre: {userData.name}\u003c/Text\u003e\n      \u003cText\u003eEmail: {userData.email}\u003c/Text\u003e\n      {/* Resto del UI */}\n    \u003c/View\u003e\n  );\n};\n```\n\n### Personalizar Componentes Reutilizables\n\n```jsx\n// Components/CustomButton.js\nimport React from 'react';\nimport { TouchableOpacity, Text, StyleSheet } from 'react-native';\n\nconst CustomButton = ({ \n  title, \n  onPress, \n  type = 'primary', // 'primary', 'secondary', 'outline'\n  size = 'medium', // 'small', 'medium', 'large'\n  disabled = false,\n  style = {}\n}) =\u003e {\n  return (\n    \u003cTouchableOpacity\n      onPress={onPress}\n      disabled={disabled}\n      style={[\n        styles.button,\n        styles[type],\n        styles[size],\n        disabled \u0026\u0026 styles.disabled,\n        style\n      ]}\n    \u003e\n      \u003cText style={[\n        styles.text,\n        styles[`${type}Text`],\n        disabled \u0026\u0026 styles.disabledText\n      ]}\u003e\n        {title}\n      \u003c/Text\u003e\n    \u003c/TouchableOpacity\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  button: {\n    borderRadius: 8,\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n  primary: {\n    backgroundColor: '#2196F3',\n  },\n  secondary: {\n    backgroundColor: '#FF9800',\n  },\n  outline: {\n    backgroundColor: 'transparent',\n    borderWidth: 1,\n    borderColor: '#2196F3',\n  },\n  small: {\n    paddingVertical: 6,\n    paddingHorizontal: 12,\n  },\n  medium: {\n    paddingVertical: 10,\n    paddingHorizontal: 16,\n  },\n  large: {\n    paddingVertical: 14,\n    paddingHorizontal: 24,\n  },\n  disabled: {\n    backgroundColor: '#CCCCCC',\n    borderColor: '#CCCCCC',\n  },\n  text: {\n    fontWeight: 'bold',\n  },\n  primaryText: {\n    color: 'white',\n  },\n  secondaryText: {\n    color: 'white',\n  },\n  outlineText: {\n    color: '#2196F3',\n  },\n  disabledText: {\n    color: '#888888',\n  },\n});\n\nexport default CustomButton;\n\n// Uso del componente personalizado\nimport CustomButton from './Components/CustomButton';\n\nconst Screen = () =\u003e {\n  return (\n    \u003cView\u003e\n      \u003cCustomButton \n        title=\"Botón Primario\" \n        onPress={() =\u003e alert('Primario!')} \n      /\u003e\n      \u003cCustomButton \n        title=\"Botón Secundario\" \n        type=\"secondary\" \n        size=\"large\" \n        onPress={() =\u003e alert('Secundario!')} \n      /\u003e\n      \u003cCustomButton \n        title=\"Botón Outline\" \n        type=\"outline\" \n        size=\"small\" \n        onPress={() =\u003e alert('Outline!')} \n      /\u003e\n      \u003cCustomButton \n        title=\"Botón Deshabilitado\" \n        disabled={true} \n        onPress={() =\u003e alert('No se ejecutará')} \n      /\u003e\n    \u003c/View\u003e\n  );\n};\n```\n\n## 1️⃣3️⃣ Depuración y Herramientas\n\n### Console.log para debugging:\n\n```jsx\nconst MiComponente = () =\u003e {\n  const datos = { nombre: 'Juan', edad: 30 };\n  \n  console.log('Datos actuales:', datos);\n  console.warn('Advertencia importante');\n  console.error('Error crítico');\n  \n  return \u003cView\u003e...\u003c/View\u003e;\n};\n```\n\n### Uso de React DevTools:\n\n1. Instala React DevTools:\n```bash\nnpm install -g react-devtools\n```\n\n2. Ejecuta en otra terminal:\n```bash\nreact-devtools\n```\n\n3. Conecta tu aplicación (sigue las instrucciones en pantalla)\n\n## 1️⃣4️⃣ Optimizaciones de Rendimiento\n\n### Uso de `React.memo` para componentes puros:\n\n```jsx\nimport React, { memo } from 'react';\nimport { Text } from 'react-native';\n\nconst MiComponente = memo(({ texto }) =\u003e {\n  console.log('Renderizando MiComponente');\n  return \u003cText\u003e{texto}\u003c/Text\u003e;\n});\n\nexport default MiComponente;\n```\n\n### `useMemo` para cálculos costosos:\n**`useMemo`**: memoriza valores computados para evitar cálculos innecesarios en cada render.\nSe usa cuando tienes funciones costosas o cálculos que no deberían ejecutarse si sus dependencias no han cambiado.\n\n```jsx\nimport React, { useMemo } from 'react';\nimport { View, Text } from 'react-native';\n\nconst ListaFiltrada = ({ items, filtro }) =\u003e {\n  const itemsFiltrados = useMemo(() =\u003e {\n    console.log('Calculando filtro...');\n    return items.filter(item =\u003e item.includes(filtro));\n  }, [items, filtro]); // Solo recalcula si items o filtro cambian\n  \n  return (\n    \u003cView\u003e\n      {itemsFiltrados.map(item =\u003e (\n        \u003cText key={item}\u003e{item}\u003c/Text\u003e\n      ))}\n    \u003c/View\u003e\n  );\n};\n```\n\n### `useCallback` para funciones:\nSirve para memorizar funciones, evitando que se vuelvan a crear en cada render. Esto mejora el rendimiento al evitar que componentes hijos innecesariamente se vuelvan a renderizar.\n\n```jsx\nimport React, { useState, useCallback } from 'react';\nimport { View, Button } from 'react-native';\n\nconst Contador = () =\u003e {\n  const [contador, setContador] = useState(0);\n  \n  // useCallback evita recrear la función en cada renderizado\n  const incrementar = useCallback(() =\u003e {\n    setContador(c =\u003e c + 1);\n  }, []); // Array vacío = no depende de ningún valor\n  \n  return (\n    \u003cView\u003e\n      \u003cButton title={`Contador: ${contador}`} onPress={incrementar} /\u003e\n    \u003c/View\u003e\n  );\n};\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furian121%2Freact-native-guia-completa-componentes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furian121%2Freact-native-guia-completa-componentes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furian121%2Freact-native-guia-completa-componentes/lists"}