Probablemente hayas chocado con la misma pared que muchos equipos de React Native chocan con el NativeBase Picker. El desplegable se renderiza, se ve bien, iOS funciona correctamente, y luego Android ignora tu onValueChange logic. Sin crash. Sin advertencia. Solo un selector que aparece funcional mientras tu lógica de negocio nunca se ejecuta.
Esa 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.
Contenido de la Tabla
- Configuración inicial con el NativeBase Picker
- Asociar Estado y Manejar Selecciones
- Resolviendo el problema de Android onValueChange
- Estilizar y personalizar su componente de selector
- Escenarios avanzados y mejores prácticas
- Conclusión
Iniciación con el selector de NativeBase
A los componentes de selección de país, estado, tipo de cita y opciones de envío les gusta sentirse pequeños hasta que el comportamiento de la plataforma comienza a filtrarse en la interfaz de usuario.
La buena noticia es que el Picker de NativeBase es fácil de poner en pantalla. Fue diseñado para renderizar un selector nativo en iOS y Android y para reemplazar el selector de React Native obsoleto en las configuraciones de NativeBase más antiguas, por lo que muchos legados de código siguen dependiendo de é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 picker más simple posible.
Si está trabajando en estacks móviles y híbridos, 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 Capacitor. El selector code sigue siendo familiar, pero las expectativas de despliegue cambian.
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 debería responder solo 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.
- ¿La ruta de importación es correcta: Los proyectos de NativeBase a menudo fallan por razones aburridas como mezclar APIs de componentes antiguos y nuevos.
- ¿El valor seleccionado está controlado: Even en un prototipo de desecho, utilice
selectedValueDesde el estado. Un picker no controlado code se vuelve más difícil de depurar más adelante.
Regla práctica: Ese baseline despojado importa. Cuando Android comienza a comportarse mal más tarde, sabrás que el problema no es tu arquitectura de formulario completa. Es el selector.
Esa base de línea minimalista es importante. Cuando Android comience a comportarse mal más adelante, sabrás que el problema no es tu arquitectura de formulario completa. Es el selector.
Estado de vinculación y manejo de selecciones
Una vez que el selector se renderiza, la siguiente tarea 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 ella selectedValuey actualiza ese estado dentro de onValueChangeEste es el mismo enfoque que usarías para otros campos de formulario como los patrones de React Native TextInputaunque el control de interfaz sea diferente.
Usa un valor controlado desde el principio
Aquí está la versión limpia a la que recurriría antes de agregar validación o efectos secundarios:
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>
</>
);
}
Eso code te da una fuente de verdad predecible. La interfaz de usuario refleja rolete da una fuente de verdad predecible. La interfaz refleja
y cada función downstream lee del mismo estado.
Los problemas suelen comenzar cuando los desarrolladores sobrecargan onValueChangeEllos recuperan datos, mutan varias porciones de estado, desencadenan navegación y registran análisis en una función inline.
Un patrón mejor es separar el almacenamiento de valores de los efectos laterales:
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>
</>
);
}
Esta estructura hace dos cosas útiles:
- Hace que el selector sea responsable solo de actualizar el estado de selección.
- Mueve el comportamiento de la aplicación a
useEffectdónde 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 seleccionó, todos los efectos laterales asociados a él se vuelven sospechosos.
Este punto se vuelve crítico en Android, donde el flujo de eventos del selector NativeBase no siempre se cumple.
Resolviendo el problema de Android onValueChange
Esto es lo que la mayoría de los artículos omiten. El selector NativeBase puede parecer saludable en Android mientras falla en el momento exacto en que necesita hacer trabajo.
La documentación de la comunidad sobre la implementación de selector más antigua describe una verdadera división entre plataformas. Android no desencadena funciones personalizadas adjuntas a onValueChangemientras que iOS síy esa falla se describe como una 100% de disparidad funcional en Android con un 0% de éxito en la activación de funciones en dispositivos Android a pesar de una implementación idéntica code. en los informes documentados. La misma documentación apunta a los desarrolladores hacia soluciones alternativas o migración, y señala que la NativeBase 3.0 Select el componente alcanza un éxito del 98% en la activación de funciones en ambas plataformas en entornos probados en comparación, tal como se describe en el Documentación y contexto de migración de NativeBase picker.

¿Qué realmente falla en Android?
La razón práctica es un detalle de implementación. En Android, el NativeBase Picker depende del spinner nativo, y ese nivel no propaga los escuchadores de eventos a la capa del wrapper de la manera en que muchos desarrolladores esperan. En iOS, el comportamiento modal se vincula correctamente al sistema de eventos.
Por eso, este error puede parecer engañoso. Ves la interfaz de usuario. Puedes abrir las opciones. Puedes incluso seleccionar un elemento visible. Pero tu función de negocio nunca se ejecuta.
Un patrón de falla 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.
Un trabajo alrededor que funciona en producción
El trabajo de compensación más confiable es arquitectónico, no estético. 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 se mantiene central: Tu lógica de componente observa
status, no el payload de evento del selector solo. - Los efectos secundarios se vuelven explícitos: llamadas API, actualizaciones de campos dependientes y seguimiento ya no viven dentro de una llamada a una función de UI frágil.
- El code es más fácil de reemplazar más tarde: If se muda de NativeBase Picker, la mayoría de la lógica de negocio sobrevive sin cambios.
Para proyectos con énfasis en Android, también recomiendo probar en un dispositivo real temprano, especialmente si su aplicación ya tiene complejidad de empaque nativo como Configuración de Android para aplicaciones Capacitor.
Cuando 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. En ese punto, moverse a NativeBase 3.0 Select 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 se mantiene el selector antiguo, trátelo como una caja de UI con responsabilidad mínima. Ese enfoque previene muchas regresiones silenciosas de Android.
Estilización y Tematización de su Componente de Selector
Un selector que funciona todavía parece inacabado si no se ajusta al resto de la aplicación. NativeBase le da suficientes patadas para hacer que el control se sienta deliberado, pero los resultados más limpios suelen provenir de estilizar el contenedor alrededor del selector en lugar de luchar directamente con el control nativo.

Estilice el contenedor antes de estilizar el selector
La propia selección está parcialmente limitada por la renderización nativa. El contenedor le da mucho más control sobre el espacio, el tratamiento de bordes y el ritmo de la disposición.
Un patrón práctico:
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,
},
});
Normalmente, ese enfoque le da la mayoría de lo que necesita sin sobrediseñar las sobrescripciones de tema.
Usar 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 selección.
Reajustes útiles incluyen:
- En iOS: Déle al campo espacio para respirar y preste atención a cómo la presentación modal se relaciona con las etiquetas circundantes.
- En Android: Check text clipping and default spinner height on multiple devices.
- Para ambos: Mantenga el texto de lugar visualmente distinto de las selecciones reales.
Una breve comparación ayuda:
| Preocupación | iOS | Android |
|---|---|---|
| Comportamiento abierto | Sentido modal | Sentido de cargador |
| Expectativas de icono | A menudo más decorativo | A menudo más funcional |
| Problemas de espaciado | Placeholder layout can feel loose | El texto puede parecer apretado |
Si su interfaz incluye gradientes, tarjetas superpuestas o superficies de alta contraste, alinee el contenedor del selector con el mismo tratamiento que se utiliza en otras partes de la interfaz, de la misma manera que los patrones utilizados en React Native linear gradient UI work.
Nota de diseño: Los usuarios juzgan un picker menos por el menú desplegable en sí y más por cómo se ajusta el campo cerrado dentro de la forma.
Por eso el radio de curvatura de la bordura, el espacio de la 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 se presentan después de que el componente sale de la fase de prototipo. El problema comienza cuando las opciones provienen de un servidor, las reglas de validación difieren por plataforma y el lugar de relleno 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 que el lugar de relleno sea seleccionable, sin embargo, el material oficial a menudo no aborda directamente ese camino. La discusión de la comunidad destaca queel valor del lugar de relleno puede permanecer seleccionable en iOS , lo que conduce a un comportamiento inconsistente en aplicaciones reales, como se menciona en esta.

Load picker options from server data safely
El error que veo con más frecuencia es tratar los datos recuperados como listos para el selector de inmediato. Mantén una capa de transformación pequeña entre tu respuesta API y el componente.
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>
);
}
Este paso de formateo te da un contrato estable. Tu selector no necesita saber la forma interna del API.
Evita la selección de relleno en iOS
La regla más segura es simple. No trates el lugar holder como una opción real, incluso si la biblioteca de UI lo hace fácil de renderizar.
Un patrón práctico:
- Usa un valor de sentinela vacío: Conserva el valor del lugar en blanco como
''o otro valor de aplicación inválido. - Valida antes de enviar: Rechazar el valor vacío en la validación de formularios, no solo en la interfaz de usuario.
- Desactivar acciones descendentes: No habilite el botón de envío hasta que exista un valor no de relleno.
Para flujos más estrictos, renderice texto de ayuda cuando el relleno permanece seleccionado:
const isValidSelection = selectedCategory !== '';
Luego bloquee sus botones de acción o llamadas de API en lugar de confiar en la presentación del selector.
Accesibilidad y hábitos de producción
Los selectores a menudo pasan por las revisiones de accesibilidad porque parecen nativos. Aún así, necesitan etiquetas claras y un estado predecible.
Unos pocos hábitos dan resultados rápidos:
- Agregar etiquetas de accesibilidad: Hacer que el campo sea comprensible para lectores de pantalla.
- Mantener las etiquetas explícitas: “País” es mejor que “Seleccionar”.
- Probar la restauración del estado: Reabrir una forma y confirmar que el elemento seleccionado anteriormente aparece correctamente.
- Write unit tests around selection-driven logic: La lógica fuera de la interfaz de usuario importa más. ayuda a proteger esas transiciones de estado. ayuda a proteger esas transiciones de estado.
Los cambios de estado detrás de él suelen ser los más críticos.
That’s the mindset that keeps dynamic forms stable. Treat the NativeBase Picker as an input surface. Put the actual rules in your state, validation, and submission flow.
Conclusion
The NativeBase Picker is still useful when you understand where it breaks. Setup is straightforward, styling is workable, and server-driven option lists are manageable. A critical trap is Android event handling. If you keep business logic out of fragile picker callbacks and move it into state-driven effects, the component becomes much more predictable.
Para códigobases antiguos, esa solución de trabajo suele ser suficiente. Para flujos críticos, migrar a Select es usualmente la mejor inversión. De cualquier manera, la clave es la misma. No confíes en el selector solo porque se renderiza.
Si su equipo envía aplicaciones Capacitor o Electron y quiere empujar correcciones de JavaScript, CSS, copia, configuración y activos sin esperar a la revisión de la tienda, Capgo es un buen punto de partida. Te ofrece 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 la interfaz de usuario como las regresiones del selector escapen a la producción.