Probablemente hayas golpeado la misma pared que muchos equipos de React Native golpean con el NativeBase Picker. El desplegable se renderiza, se ve bien, iOS se comporta correctamente, y luego Android ignora tu onValueChange lógica. Sin crash. Sin advertencia. Solo un selector que aparece funcional mientras tu lógica empresarial nunca se ejecuta.
That brecha es por qué el NativeBase Picker todavía sorprende a los desarrolladores experimentados. La configuración es simple, el estilo es manejable, pero la confiabilidad en producción depende de entender una falla específica de Android que la mayoría de las guías omiten o nunca mencionan.
Índice
- Comenzar con el NativeBase Picker
- Establecer el estado y manejar las selecciones
- Solucionar el problema del bug onValueChange de Android
- Estilo y Tema de su Componente de Selección
- Escenarios Avanzados y Mejores Prácticas
- Conclusión
Empezar con el Picker Nativo de NativeBase
Un picker es normalmente uno de esos componentes que agregas tarde en una sprint. Selección de país, campo de estado, tipo de cita, opción de envío. Siente que es pequeño hasta que el comportamiento de la plataforma comienza a filtrarse en tu interfaz de usuario.
La buena noticia es que el Picker Nativo de NativeBase es fácil de obtener en pantalla. Fue construido para renderizar un selector nativo en iOS y Android y para reemplazar el selector de React Native obsoleto en configuraciones de NativeBase más antiguas, por lo que muchas bases de código legadas siguen confiando en él.

Instale el componente en un setup de React Native normal
Si su proyecto ya utiliza NativeBase, la tarea principal es importar las primitivas adecuadas y evitar la lógica de envoltura innecesaria desde el primer día. Comience con el selector de fecha más simple posible.
Si está trabajando en pilas móviles y híbridas, también ayuda a entender cómo React code se empaqueta en entornos más amplios como Flujos de trabajo de aplicaciones móviles de React con CapacitorEl selector code sigue siendo familiar, pero cambian las expectativas de despliegue.
Un ejemplo básico se ve así:
import React, { useState } from 'react';
import { Container, Content, Form, Item, Picker, Icon } from 'native-base';
export default function BasicPickerScreen() {
const [selectedValue, setSelectedValue] = useState('key0');
return (
<Container>
<Content padder>
<Form>
<Item picker>
<Picker
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
selectedValue={selectedValue}
onValueChange={(value) => setSelectedValue(value)}
>
<Picker.Item label="Choose one" value="key0" />
<Picker.Item label="JavaScript" value="js" />
<Picker.Item label="TypeScript" value="ts" />
<Picker.Item label="React Native" value="rn" />
</Picker>
</Item>
</Form>
</Content>
</Container>
);
}
Renderice un primer selector sin abstracción adicional
Esta primera pasada debe responder solo a dos preguntas:
- ¿Se renderiza correctamente: Quieres verificar que el campo aparece dentro de tu diseño, respeta el espacio y se abre en ambas plataformas.
- ¿Está correcto el camino de importación: Los proyectos de NativeBase a menudo fallan por razones aburridas como mezclar APIs de componentes antiguos y nuevos.
- ¿Está el valor seleccionado controlado: Even in a throwaway prototype, use
selectedValuefrom state. Uncontrolled picker code se vuelve más difícil de depurar más tarde.
Regla práctica: No comience mapeando datos de servidor, reglas de reemplazo, hooks de análisis y validación en el mismo selector. Primero haga que el componente esté visible y controlado.
Esas líneas base despejadas importan. Cuando Android comience a comportarse mal más tarde, sabrá que el problema no es su arquitectura de formulario completa. Es el selector.
Unir Estado y Manejar Selecciones
Una vez que el selector se renderiza, el siguiente trabajo es hacerlo útil. En React Native, eso significa tratarlo como un input controlado y mantener el valor seleccionado en el estado del componente.
El camino estándar es directo. Almacena el valor actual con useStatepasarlo a selectedValueactualice ese estado dentro de. onValueChangeUsa el mismo patrón que para otros campos de formulario como patrones de TextInput de React NativeSi bien el control de interfaz es diferente.
Usa un valor controlado desde el principio
La versión limpia que yo elegiría antes de agregar validación o efectos secundarios es:
import React, { useState } from 'react';
import { Text } from 'react-native';
import { Form, Item, Picker } from 'native-base';
export default function RolePicker() {
const [role, setRole] = useState('');
return (
<>
<Form>
<Item picker>
<Picker
mode="dropdown"
selectedValue={role}
onValueChange={(value) => setRole(value)}
>
<Picker.Item label="Select a role" value="" />
<Picker.Item label="Admin" value="admin" />
<Picker.Item label="Editor" value="editor" />
<Picker.Item label="Viewer" value="viewer" />
</Picker>
</Item>
</Form>
<Text>Selected role: {role || 'none'}</Text>
</>
);
}
Es ese code lo que te da una fuente de verdad predecible. La interfaz refleja roley cada función downstream lee de la misma fuente de verdad.
Mantén la lógica de selección pequeña y probada
Los problemas suelen comenzar cuando los desarrolladores sobrecargan onValueChangeEllos fetch data, mutan varias porciones de estado, desencadenan navegación y envían analytics en una función inline. Cuando falla el comportamiento del selector, el depurado se vuelve doloroso.
Un patrón mejor es separar el almacenamiento de valores de los efectos secundarios:
import React, { useEffect, useState } from 'react';
import { Text } from 'react-native';
import { Form, Item, Picker } from 'native-base';
export default function DepartmentPicker() {
const [department, setDepartment] = useState('');
const [message, setMessage] = useState('No department selected');
useEffect(() => {
if (!department) {
setMessage('No department selected');
return;
}
setMessage(`Department selected: ${department}`);
}, [department]);
return (
<>
<Form>
<Item picker>
<Picker
selectedValue={department}
onValueChange={setDepartment}
>
<Picker.Item label="Select department" value="" />
<Picker.Item label="Sales" value="sales" />
<Picker.Item label="Support" value="support" />
<Picker.Item label="Operations" value="operations" />
</Picker>
</Item>
</Form>
<Text>{message}</Text>
</>
);
}
This structure realiza dos cosas útiles:
- Esto hace que el selector sea responsable solo de actualizar el estado de selección.
- Hace que el comportamiento de la aplicación se mueva a
useEffect, donde puedes probar y razonar sobre él de manera independiente.
Si un componente de formulario no puede informar con confianza a tu aplicación qué valor seleccionado es, todos los efectos secundarios asociados a él se vuelven sospechosos.
Este punto se vuelve crítico en Android, donde el flujo de eventos de la Picker de NativeBase no siempre se cumple.
Solución del problema de Android onValueChange
Esta es la parte que omiten los artículos. La Picker de NativeBase puede parecer saludable en Android mientras falla en el exacto momento en que necesita hacer trabajo.
La documentación de la comunidad alrededor de la implementación de la picker más antigua describe una verdadera división entre plataformas. Android no dispara funciones personalizadas asociadas a onValueChange, mientras que iOS sí,, y esa falla se describe como un desigualdad funcional del 100% en Android con una tasa de éxito del 0% para la activación de funciones en dispositivos Android a pesar de una implementación code idéntica en los informes documentados. Los mismos informes apuntan a los desarrolladores hacia soluciones alternativas o migración, y destacan que el NativeBase 3.0 Select componente alcanza el 98% de éxito en la activación de funciones en ambas plataformas en entornos probados en comparación, tal como se describe en el documento de NativeBase picker y contexto de migración.

¿Qué realmente se rompe en Android
La razón práctica es un detalle de implementación. En Android, el NativeBase Picker se basa en el desplegable nativo, y esa capa no propaga los escuchadores de eventos a la capa del contenedor de la manera en que muchos desarrolladores esperan. En iOS, el comportamiento basado en modal se une correctamente al sistema de eventos.
Es por eso que este error siente engañoso. Ves la interfaz de usuario. Puedes abrir las opciones. Puedes incluso seleccionar un elemento visible. Pero tu función empresarial nunca se ejecuta.
Un patrón fallido típico se ve así:
<Picker
selectedValue={status}
onValueChange={(value) => {
setStatus(value);
saveStatusToApi(value);
trackSelection(value);
updateDependentFields(value);
}}
>
En iOS, esto puede comportarse exactamente como se espera. En Android, el selector puede renderizarse mientras que esas funciones nunca se disparan.
Una solución alternativa que funciona en producción
La solución alternativa más confiable es arquitectónica, no estética. Mantén la interacción del selector enfocada en almacenar un valor seleccionado, luego reacciona a los cambios de estado fuera del manipulador del selector.
import React, { useEffect, useState } from 'react';
import { Form, Item, Picker } from 'native-base';
export default function StatusPicker() {
const [status, setStatus] = useState('');
const [didMount, setDidMount] = useState(false);
useEffect(() => {
if (!didMount) {
setDidMount(true);
return;
}
if (!status) return;
runStatusSideEffects(status);
}, [status, didMount]);
const runStatusSideEffects = (value) => {
console.log('Selected status:', value);
// call validation, API sync, or dependent form updates here
};
return (
<Form>
<Item picker>
<Picker
selectedValue={status}
onValueChange={setStatus}
>
<Picker.Item label="Select status" value="" />
<Picker.Item label="Pending" value="pending" />
<Picker.Item label="Approved" value="approved" />
<Picker.Item label="Rejected" value="rejected" />
</Picker>
</Item>
</Form>
);
}
¿Por qué esto ayuda:
- El estado permanece centralizado: La lógica de tu componente vigila
status, y no solo el payload del evento del selector. - Los efectos secundarios se vuelven explícitos: Las llamadas a API, actualizaciones de campos dependientes y seguimiento ya no viven dentro de una llamada de callback UI frágil.
- El code es más fácil de reemplazar más tarde: Si migras a una solución alternativa a NativeBase Picker, la mayoría de la lógica empresarial sobrevive sin cambios.
Para proyectos con énfasis en Android, también recomiendo probar en un dispositivo real temprano, especialmente si tu aplicación ya tiene complejidad de empaque nativo, como Configuración de Android para aplicaciones Capacitor.
When migrar a Select es la decisión más limpia
Si el selector se encuentra en un flujo crítico como el pago, el registro, o la entrada de datos regulados, parchear alrededor del comportamiento antiguo puede no ser merecedor. Select En ese punto, moverse a NativeBase 3.0
es usualmente la llamada más segura a largo plazo.
El error no es solo una molestia. Cambia dónde puedes colocar lógica de negocio de manera segura.
Si mantienes el selector antiguo, tratalo como una caja de diálogo de interfaz de usuario con responsabilidad mínima. Ese enfoque previene muchas regresiones silenciosas en Android.
Estilizar y Tematizar tu Componente de Selector

Una mano sosteniendo un smartphone que muestra una aplicación de reserva de viajes con un menú desplegable de selector de base nativa.
Estiliza el contenedor antes de estilizar el selector
El selector mismo está en parte limitado por la representación nativa. El contenedor te da mucho más control sobre el espacio, el tratamiento de bordes y el ritmo de la disposición.
import React, { useState } from 'react';
import { StyleSheet } from 'react-native';
import { Form, Item, Picker, Icon } from 'native-base';
export default function StyledPicker() {
const [country, setCountry] = useState('');
return (
<Form>
<Item style={styles.pickerWrapper} picker>
<Picker
mode="dropdown"
iosIcon={<Icon name="arrow-down" style={styles.icon} />}
textStyle={styles.pickerText}
selectedValue={country}
onValueChange={setCountry}
>
<Picker.Item label="Select country" value="" />
<Picker.Item label="Germany" value="de" />
<Picker.Item label="Japan" value="jp" />
<Picker.Item label="Brazil" value="br" />
</Picker>
</Item>
</Form>
);
}
const styles = StyleSheet.create({
pickerWrapper: {
borderWidth: 1,
borderColor: '#D1D5DB',
borderRadius: 10,
marginTop: 12,
paddingLeft: 8,
backgroundColor: '#FFFFFF',
},
pickerText: {
color: '#111827',
fontSize: 16,
},
icon: {
color: '#111827',
fontSize: 18,
},
});
Un patrón práctico:
Use presentación consciente de la plataforma
iOS y Android rara vez necesitan estilos idénticos. Necesitan intención consistente. El mismo token visual todavía puede requerir diferentes espaciados, colocación de iconos o modo de selector.
Las ajustaciones útiles incluyen:
- Sobre iOS: Dé al campo espacio para respirar y preste atención a cómo la presentación modal se relaciona con las etiquetas circundantes.
- Sobre Android: Verifique el corte de texto y la altura predeterminada del selector en múltiples dispositivos.
- Para ambos: Mantenga el texto de lugar visualmente distinto de las selecciones reales.
Una breve comparación ayuda:
| Preocupación | Sobre iOS | Android |
|---|---|---|
| Comportamiento abierto | Sentido modal | Sentido de giratoria |
| Expectativas de icono | A menudo más decorativo | A menudo más funcional |
| Problemas de espaciado | La disposición de reemplazo puede sentirse floja | El texto puede sentirse apretado |
Si tu interfaz incluye gradientes, tarjetas superpuestas o superficies de contraste alto, alinea el contenedor del selector con el mismo tratamiento que usas en otros lugares de la interfaz, de la misma manera que los patrones utilizados en Trabajo de gradiente lineal de React Native UI.
Nota de diseño: Los usuarios juzgan un selector menos por el menú desplegable en sí y más por cómo el campo cerrado se sienta dentro de la forma.
Por eso, el radio de borde, el espacio de etiqueta y el color del placeholder importan más que la personalización exótica del selector.
Escenarios avanzados y mejores prácticas
La mayoría de los errores de selector aparecen después de que el componente sale de la fase de prototipo. El problema comienza cuando las opciones vienen de un servidor, las reglas de validación difieren por plataforma y el placeholder no puede actuar como un valor válido.
Un caso de borde recurrente es especialmente molesto en iOS. Los desarrolladores a menudo necesitan cargar valores de selector desde un servidor mientras se impide la selección del valor de placeholder, sin embargo, el material oficial a menudo no aborda directamente ese camino. La discusión de la comunidad destaca queel valor de placeholder puede permanecer seleccionable en iOS lo que conduce a un comportamiento inconsistente en aplicaciones reales, como se menciona en esta.

Un diagrama que ilustra el proceso de cuatro pasos de flujo de datos para utilizar un selector dinámico en NativeBase.
The mistake I see most often is treating fetched data as immediately picker-ready. Keep a small transformation layer between your API response and the component.
import React, { useEffect, useState } from 'react';
import { Form, Item, Picker } from 'native-base';
export default function DynamicCategoryPicker() {
const [categories, setCategories] = useState([]);
const [selectedCategory, setSelectedCategory] = useState('');
useEffect(() => {
const loadCategories = async () => {
const response = await fetch('https://example.com/api/categories');
const data = await response.json();
const formatted = data.map((item) => ({
label: item.name,
value: String(item.id),
}));
setCategories(formatted);
};
loadCategories();
}, []);
return (
<Form>
<Item picker>
<Picker
selectedValue={selectedCategory}
onValueChange={setSelectedCategory}
>
<Picker.Item label="Select category" value="" />
{categories.map((item) => (
<Picker.Item
key={item.value}
label={item.label}
value={item.value}
/>
))}
</Picker>
</Item>
</Form>
);
}
Ese paso de formato te da un contrato estable. Tu selector no necesita saber la forma interna del API.
Prevenir la selección de marcadores de posición en iOS
La regla más segura es simple. No trates al marcador de posición como una opción real, incluso si la biblioteca de interfaz de usuario lo hace fácil de renderizar.
Un patrón práctico:
- Usar un valor de sentinela vacío: Mantén el valor del marcador de posición como
''o otro valor de aplicación inválido. - Validar antes de enviar: Rechaza el valor vacío en la validación de formularios, no solo en la interfaz de usuario.
- Deshabilitar acciones posteriores: No habilite el botón de enviar hasta que exista un valor no de marcador de posición.
Para flujos más estrictos, renderice texto de ayuda cuando el marcador de posición sigue seleccionado:
const isValidSelection = selectedCategory !== '';
Entonces, bloquee sus botones de acción o API llamadas en lugar de confiar en la presentación del selector.
Hábitos de accesibilidad y producción
Los selectores a menudo pasan por las revisiones de accesibilidad porque parecen nativos. Sin embargo, todavía necesitan etiquetas claras y un estado predecible.
Unos pocos hábitos dan resultados rápidamente:
- Agregue etiquetas de accesibilidad: Haga que el campo sea comprensible para los lectores de pantalla.
- Mantenga las etiquetas explícitas: ‘País’ es mejor que ‘Seleccionar’.
- Pruebe la restauración del estado: Reabra un formulario y confirme que el elemento seleccionado anteriormente aparece correctamente.
- Escriba pruebas unitarias alrededor de la lógica impulsada por la selección: La lógica fuera de la interfaz de usuario es lo que importa más, y pruebas unitarias de comportamiento de React te ayuda a proteger esas transiciones de estado.
Un selector es raramente crítico por sí solo. Los cambios de estado detrás de él suelen ser.
Ese es el mindset que mantiene las formas dinámicas estables. Trata al Picker de NativeBase como una superficie de entrada. Coloca las reglas reales en tu flujo de estado, validación y envío.
Conclusiones
El Picker de NativeBase todavía es útil cuando entiendes dónde se rompe. La configuración es sencilla, el estilo es trabajable y las listas de opciones impulsadas por el servidor son manejables. Un trampa crítica es el manejo de eventos de Android. Si mantienes la lógica empresarial fuera de las llamadas de retorno del picker frágil y la mueves a efectos impulsados por el estado, el componente se vuelve mucho más predecible.
Para códigobases más antiguas, ese workaround suele ser suficiente. Para flujos críticos, migrar a Select generalmente es una mejor inversión. De cualquier manera, la clave es la misma. No confíes en el picker solo porque se renderiza.
Si tu equipo envía Capacitor o aplicaciones de Electron y quiere empujar arreglos de JavaScript, CSS, copia, configuración y activos sin esperar a que se apruebe la tienda, Capgo es digno de una mirada. Te da actualizaciones en vivo firmadas, control de lanzamiento, protección de rollback y visibilidad de lanzamiento para que puedas recuperarte más rápido cuando los bugs de interfaz de usuario como las regresiones del selector escapen a la producción.