Renderizar una lista de OBJETOS en React Native (y por qué no usa useState)

 

🎯 Objetivo

  1. Entender cómo renderizar un array de objetos con .map().

  2. Entender por qué este ejemplo NO necesita useState.

  3. 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:

text
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)

jsx
const usuarios = ['Ana', 'Carlos', 'Luisa', 'Pedro'];

Cada ítem es un solo valor (un nombre).

Array de objetos (este ejemplo)

jsx
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

jsx
// 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

text
👤 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

jsx
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()

jsx
usuarios.map((usuario) => (...))
  • Recorre cada objeto del array.

  • usuario es 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

jsx
<View key={usuario.id} style={styles.tarjeta}>
  • key={usuario.id} → usa el id ú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

jsx
<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

jsx
<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

useState solo 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❌ NoLos 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❌ NoNunca cambian
Colores de un tema❌ NoSon 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:

  1. Guarda un valor entre renders.

  2. 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.

jsx
// ❌ Innecesario
const [usuarios, setUsuarios] = useState([...]);
// Nunca llamas setUsuarios → useState no aporta nada

// ✅ Correcto
const usuarios = [...];
// Es una constante, no cambia, no re-renderiza

Analogía: useState es 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.

jsx
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.

jsx
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):

jsx
// 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

AspectoSin useStateCon 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 usarloDatos fijosDatos 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

text
┌─────────────────────────────────────────────┐
│  ¿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

  1. Un array de objetos se recorre igual con .map(), pero cada ítem tiene varias propiedades.

  2. Para acceder a las propiedades: usuario.nombre, usuario.edad, etc.

  3. Se usa key={usuario.id} (mejor que index).

  4. useState solo se usa si el valor cambia y debe reflejarse en pantalla.

  5. Si los datos son fijos → constante, no useState.

  6. 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.

useState es 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

Entradas más populares de este blog

9. Componente SafeArea

Pasar funciones como props, explicado con analogías

Comunicación entre Padre e Hijo con Funciones en React Native