Renderizar una lista de OBJETOS en React Native (y por qué no usa useState)
🎯 Objetivo
Entender cómo renderizar un array de objetos con
.map().Entender por qué este ejemplo NO necesita
useState.Entender la diferencia entre "solo renderizar" y "renderizar + cambiar".
🧠 Analogía principal: el menú del restaurante 📜
Un array de objetos es como el menú de un restaurante:
Plato 1: { nombre: 'Milanesa', precio: 1500, vegano: false }
Plato 2: { nombre: 'Ensalada', precio: 800, vegano: true }
Plato 3: { nombre: 'Pizza', precio: 1200, vegano: false }Cada plato tiene varias propiedades (nombre, precio, etc.).
El menú es fijo, no cambia mientras el cliente lo lee.
Solo hay que mostrarlo en la pantalla.
Analogía: si el menú nunca cambia, no necesitas
useState. Solo lo imprimes y listo.
📦 Array de strings vs. array de objetos
Array de strings (ejemplo anterior)
const usuarios = ['Ana', 'Carlos', 'Luisa', 'Pedro'];Cada ítem es un solo valor (un nombre).
Array de objetos (este ejemplo)
const usuarios = [
{ id: 1, nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
{ id: 2, nombre: 'Carlos', edad: 34, ciudad: 'Bogotá' },
{ id: 3, nombre: 'Luisa', edad: 22, ciudad: 'Lima' },
{ id: 4, nombre: 'Pedro', edad: 30, ciudad: 'Buenos Aires' },
];Cada ítem es un objeto con varias propiedades.
Analogía: antes tenías una lista de nombres sueltos; ahora tienes una lista de fichas completas de cada persona.
🔧 Código completo: lista de objetos
// components/ListaDeUsuarios.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const ListaDeUsuarios = () => {
const usuarios = [
{ id: 1, nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
{ id: 2, nombre: 'Carlos', edad: 34, ciudad: 'Bogotá' },
{ id: 3, nombre: 'Luisa', edad: 22, ciudad: 'Lima' },
{ id: 4, nombre: 'Pedro', edad: 30, ciudad: 'Buenos Aires' },
];
return (
<View style={styles.lista}>
{usuarios.map((usuario) => (
<View key={usuario.id} style={styles.tarjeta}>
<Text style={styles.nombre}>👤 {usuario.nombre}</Text>
<Text>Edad: {usuario.edad}</Text>
<Text>Ciudad: {usuario.ciudad}</Text>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
lista: { padding: 20, paddingTop: 60 },
tarjeta: {
backgroundColor: '#f2f2f2',
padding: 16,
borderRadius: 10,
marginBottom: 12,
},
nombre: { fontSize: 18, fontWeight: 'bold', marginBottom: 4 },
});
export default ListaDeUsuarios;🖥️ Resultado en pantalla
👤 Ana
Edad: 28
Ciudad: Madrid
👤 Carlos
Edad: 34
Ciudad: Bogotá
👤 Luisa
Edad: 22
Ciudad: Lima
👤 Pedro
Edad: 30
Ciudad: Buenos Aires🔍 Explicación línea por línea
1️⃣ El array de objetos
const usuarios = [
{ id: 1, nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
...
];Cada elemento es un objeto con 4 propiedades: id, nombre, edad, ciudad.
Analogía: cada uno es una ficha personal en una carpeta.
2️⃣ El .map()
usuarios.map((usuario) => (...))Recorre cada objeto del array.
usuarioes el objeto completo de esa vuelta.Para acceder a sus propiedades:
usuario.nombre,usuario.edad, etc.
Analogía:
.map()es como abrir cada ficha y leer sus datos uno por uno.
3️⃣ El key
<View key={usuario.id} style={styles.tarjeta}>key={usuario.id}→ usa elidúnico del objeto.Es mejor que
key={index}porque si la lista cambia de orden, React no se confunde.Cada objeto ya trae su propio
id→ perfecto.
Analogía: cada ficha tiene un número de legajo. No importa el orden, siempre la identificas.
4️⃣ Renderizar varias propiedades
<Text style={styles.nombre}>👤 {usuario.nombre}</Text>
<Text>Edad: {usuario.edad}</Text>
<Text>Ciudad: {usuario.ciudad}</Text>Cada propiedad se muestra en su propio
<Text>.Se combinan texto fijo (
'Edad:') con valores dinámicos ({usuario.edad}).
Analogía: en cada ficha, escribes varios renglones: nombre, edad, ciudad.
5️⃣ El contenedor View por cada ítem
<View key={usuario.id} style={styles.tarjeta}>
...
</View>En lugar de devolver un solo <Text>, devuelves una tarjeta completa (View) con varios textos adentro.
Analogía: en vez de escribir un nombre suelto, dibujas una tarjeta con todos los datos.
❓ ¿Por qué este ejemplo NO usa useState?
Esta es la pregunta clave. Vamos por partes.
🧠 La regla de oro de useState
useStatesolo se usa cuando un valor CAMBIA con el tiempo y afecta la pantalla.
Si el valor nunca cambia, no necesitas useState. Solo usas una variable normal.
🔍 Comparación directa
| Situación | ¿useState? | ¿Por qué? |
|---|---|---|
| Lista fija de usuarios | ❌ No | Los datos no cambian |
| Contador que sube | ✅ Sí | El número cambia |
| Input donde escribes | ✅ Sí | El texto cambia |
| Lista que agregas/eliminas | ✅ Sí | La lista cambia |
| Constantes de la app | ❌ No | Nunca cambian |
| Colores de un tema | ❌ No | Son fijos |
Analogía: si el menú del restaurante nunca cambia, no necesitas un pizarrón mágico. Lo imprimes y ya. Si cambia todos los días, sí necesitas el pizarrón mágico (
useState).
📌 ¿Qué hace useState exactamente?
useState hace dos cosas:
Guarda un valor entre renders.
Re-renderiza el componente cuando ese valor cambia.
Si tu dato no cambia, no necesitas ni guardarlo entre renders ni re-renderizar. Con una constante alcanza.
// ❌ Innecesario
const [usuarios, setUsuarios] = useState([...]);
// Nunca llamas setUsuarios → useState no aporta nada
// ✅ Correcto
const usuarios = [...];
// Es una constante, no cambia, no re-renderizaAnalogía:
useStatees un cajón con alarma. Si nunca cambias nada dentro del cajón, la alarma no sirve para nada. Solo usa un cajón común (una constante).
🎭 Los dos escenarios: "solo renderizar" vs "renderizar + cambiar"
🅰️ Escenario 1: SOLO RENDERIZAR (sin useState)
Los datos vienen fijos.
El componente los muestra y ya.
No hay botones, no hay input, no hay cambios.
const usuarios = [
{ id: 1, nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
...
];Casos reales:
Un menú fijo de la app.
Una lista de instrucciones.
Un listado de categorías que no cambia.
Datos hardcodeados de prueba.
Analogía: imprimir un menú y colgarlo en la pared.
🅱️ Escenario 2: RENDERIZAR + CAMBIAR (con useState)
Los datos pueden cambiar.
Hay botones para agregar, eliminar o editar.
La pantalla debe actualizarse sola.
const [usuarios, setUsuarios] = useState([
{ id: 1, nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
...
]);Casos reales:
Lista de tareas.
Carrito de compras.
Chat con mensajes nuevos.
Datos que vienen de una API.
Analogía: un pizarrón mágico donde escribes y borras todos los días.
🔄 Versión con useState: cuando SÍ cambia
Ahora sí, un ejemplo donde la lista cambia (agregar y eliminar usuarios):
// components/ListaDeUsuarios.js
import React, { useState } from 'react';
import { View, Text, Button, TextInput, FlatList, StyleSheet } from 'react-native';
const ListaDeUsuarios = () => {
const [nombre, setNombre] = useState('');
const [usuarios, setUsuarios] = useState([
{ id: '1', nombre: 'Ana', edad: 28, ciudad: 'Madrid' },
{ id: '2', nombre: 'Carlos', edad: 34, ciudad: 'Bogotá' },
]);
const agregarUsuario = () => {
if (nombre.trim() === '') return;
setUsuarios([
...usuarios,
{ id: Date.now().toString(), nombre, edad: 0, ciudad: '—' },
]);
setNombre('');
};
const eliminarUsuario = (id) => {
setUsuarios(usuarios.filter(u => u.id !== id));
};
return (
<View style={styles.container}>
<TextInput
placeholder="Nombre del nuevo usuario"
value={nombre}
onChangeText={setNombre}
style={styles.input}
/>
<Button title="Agregar" onPress={agregarUsuario} />
<FlatList
data={usuarios}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={styles.tarjeta}>
<Text style={styles.nombre}>👤 {item.nombre}</Text>
<Text>Edad: {item.edad}</Text>
<Text>Ciudad: {item.ciudad}</Text>
<Button title="🗑️ Eliminar" onPress={() => eliminarUsuario(item.id)} />
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 20, paddingTop: 60 },
input: {
borderWidth: 1,
borderColor: '#999',
padding: 10,
borderRadius: 8,
marginBottom: 10,
},
tarjeta: {
backgroundColor: '#f2f2f2',
padding: 16,
borderRadius: 10,
marginBottom: 12,
},
nombre: { fontSize: 18, fontWeight: 'bold', marginBottom: 4 },
});
export default ListaDeUsuarios;🔑 ¿Por qué aquí SÍ usamos useState?
Porque:
El usuario puede agregar (
setUsuarios([...usuarios, nuevo])).El usuario puede eliminar (
setUsuarios(usuarios.filter(...))).La pantalla debe actualizarse sola cuando eso pasa.
Analogía: el menú ahora cambia todos los días, así que necesitas el pizarrón mágico.
📊 Tabla comparativa final
| Aspecto | Sin useState | Con useState |
|---|---|---|
| Los datos cambian | ❌ No | ✅ Sí |
| Hay botones que modifican | ❌ No | ✅ Sí |
| Se re-renderiza solo | ❌ No | ✅ Sí |
Se usa .map() | ✅ Sí | ✅ Sí (o FlatList) |
Se usa key | ✅ Sí | ✅ Sí |
| Cuándo usarlo | Datos fijos | Datos dinámicos |
🧠 La regla mental definitiva
Pregúntate:
"¿Este dato va a cambiar mientras la app está abierta?"
NO → variable normal (const). Sin
useState.SÍ →
useState.
Analogía: si el menú del restaurante nunca cambia, lo imprimes (constante). Si cambia todos los días, necesitas un pizarrón mágico (
useState).
🎁 Resumen visual
┌─────────────────────────────────────────────┐
│ ¿El dato cambia con el tiempo? │
└──────────────────┬──────────────────────────┘
│
┌──────────┴──────────┐
▼ ▼
NO SÍ
│ │
▼ ▼
const datos = [...] const [datos, setDatos] = useState([...])
│ │
▼ ▼
Solo se renderiza Se renderiza + cambia
(ejemplo original) (con botones/input)📌 Puntos clave para recordar
Un array de objetos se recorre igual con
.map(), pero cada ítem tiene varias propiedades.Para acceder a las propiedades:
usuario.nombre,usuario.edad, etc.Se usa
key={usuario.id}(mejor queindex).useStatesolo se usa si el valor cambia y debe reflejarse en pantalla.Si los datos son fijos → constante, no
useState.Si los datos son dinámicos (agregar, eliminar, editar) →
useState.
🎯 Analogía final unificada
Piensa en dos restaurantes:
🍽️ Restaurante 1: menú impreso
El menú nunca cambia.
Lo imprimes una vez y lo cuelgas.
No necesitas
useState. Solo renderizas.
📝 Restaurante 2: menú del día
El menú cambia cada día.
Necesitas un pizarrón mágico donde escribes y borras.
Sí necesitas
useState. Porque cambia.
useStatees el pizarrón mágico del menú del día. Si tu menú nunca cambia, no lo necesitas.
¿Quieres que sigamos con un ejemplo donde los usuarios vengan de una API con fetch + useEffect (que combina useState para guardar los datos y renderizarlos en una FlatList)
Comentarios
Publicar un comentario