Saltar al contenido principal

Native Base Picker: Configuración, Estilo y Corrección de Android

Implementar Native Base Picker en React Native. Cubre la configuración, el estado, el estilo y una corrección crítica para el bug de onValueChange en Android. Guía rápida.

Martín Donadieu

Martín Donadieu

Gerente de Contenido

Native Base Picker: Configuración, Estilo y Corrección de Android

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, y luego Android ignora su lógica. Sin crash. Sin advertencia. Solo un selector que aparece funcional mientras su lógica empresarial nunca se ejecuta. onValueChange Martín Donadieu

Esa brecha es por qué el NativeBase Picker sigue pillando a los desarrolladores experimentados por sorpresa. 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 pasan por alto o nunca mencionan.

Contenido de la Tabla

Iniciación con el Picker de NativeBase

Un picker es normalmente uno de esos componentes que agregas tarde en una sprint. Selector 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.

La buena noticia es que el Picker 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 todavía dependen de él.

Un espacio de trabajo para desarrolladores que muestra una laptop con React Native code junto a una interfaz de aplicación móvil.

Instale el componente en una configuración de React Native normal

Si su proyecto ya utiliza NativeBase, la tarea principal es importar las primitivas correctas 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 con 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 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.
  • ¿Se controla el valor seleccionado: Even in a throwaway prototype, use selectedValue de estado. El selector no controlado code se vuelve más difícil de depurar más adelante.

Regla práctica: No comiences mapeando los datos del servidor, las reglas de relleno, los hooks de análisis y la validación en el mismo selector. Primero haz que el componente esté visible y controlado.

Esa base simplificada 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.

Uniendo Estado y Manejando 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 sencillo. Almacenas el valor actual con useStatey lo pasas a selectedValuey actualizar ese estado dentro de onValueChangeEste es el mismo enfoque que usarías para otros campos de formulario como patrones de TextInput de React Nativeincluso aunque el control de interfaz sea diferente.

Utiliza un valor controlado desde el principio

Aquí está la versión limpia a la que recurriría antes de agregar validación o efectos laterales:

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>
    </>
  );
}

Ese code te da una fuente de verdad predecible. La interfaz refleja role, y cada función downstream lee del mismo estado.

Mantén la lógica de selección pequeña y probada

Los problemas suelen comenzar cuando los desarrolladores sobrecargan onValueChange. Se cargan datos, se mutan varias porciones de estado, se desencadena la navegación y se registran análisis 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 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 realiza dos cosas útiles:

  1. Hace que el selector sea responsable solo de actualizar el estado de selección.
  2. Mueve el comportamiento de la aplicación a useEffectdonde puedes probar y razonar sobre ella de manera independiente.

Si un componente de formulario no puede informar con confianza a tu aplicación sobre el valor seleccionado, todos los efectos secundarios asociados a él se vuelven sospechosos.

Ese punto se vuelve crítico en Android, donde el flujo de eventos de NativeBase Picker no siempre se cumple.

Solucionar el problema del bug de onValueChange en Android

Esta es la parte que la mayoría de los artículos omiten. El selector de 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 dispara funciones personalizadas asociadas a onValueChangemientras que iOS síy esa falla se describe como un 100% 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 el componente NativeBase 3.0 Select componente alcanza 98% de éxito 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.

Un gráfico que muestra un error común en el componente NativeBase Picker en Android y su solución propuesta.

¿Qué realmente falla en Android?

La razón práctica es un detalle de implementación. En Android, el NativeBase Picker se basa en el spinner 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 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.

A 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: Tu lógica de componente vigila status, no el payload de evento del selector solo.
  • 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 aplicación diferente de 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 de trabajo crítico como la facturación, el registro de usuarios o la entrada de datos regulados, parchear alrededor del comportamiento antiguo puede no ser merecedor de la inversión. 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 mantienes el selector antiguo, tratalo como una caja de diálogo de usuario con responsabilidad mínima. Ese enfoque previene muchos regresiones silenciosas en Android.

Estilizar y Tematizar tu Componente de Selector

Un selector que funciona todavía parece inacabado si no se ajusta al resto de la aplicación. NativeBase te da suficientes hooks 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 contra el control nativo directamente.

Una mano sosteniendo un teléfono móvil 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.

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,
  },
});

Ese enfoque suele llevarte la mayor parte del camino sin sobrecargar los overrides de tema.

Use presentación consciente de la plataforma

iOS y Android raramente necesitan estilos idénticos. Necesitan una intención consistente. El mismo token visual todavía puede requerir diferentes espacios de padding, colocación de iconos o modo de selección.

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 control de rotación en múltiples dispositivos.
  • Para ambos: Mantenga el texto de lugar visualmente distinto de las selecciones reales.

Una breve comparación ayuda:

Preocupación iOS Android
Comportamiento al abrir Aspecto modal Aspecto de spinner
Expectativas de icono A menudo más decorativo A menudo más funcional
Problemas de espaciado La disposición del lugar de reemplazo puede parecer flojo El texto puede parecer apretado

Si tu interfaz incluye gradientes, tarjetas superpuestas o superficies de alta contraste, alinea el contenedor del selector con el mismo tratamiento que usas en otros lugares de la interfaz, de manera similar a los patrones utilizados en el trabajo de gradientes lineales de React Native React Native linear gradient UI work.

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 curvatura de la frontera, el espacio de la etiqueta y el color del lugar de relleno 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 necesitan cargar valores de selector desde un servidor mientras evitan que el lugar de relleno sea seleccionable, pero 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.

discusión de la comunidad de React Native sobre valores de selector cargados desde un servidor y selección del lugar de relleno

Un diagrama que ilustra el proceso de cuatro pasos de flujo de datos para utilizar un selector dinámico en NativeBase.

Cargar opciones de selector de datos de servidor de manera segura. El error que veo con más frecuencia es tratar los datos recuperados como inmediatamente listos para el selector. Mantén una capa de transformación pequeña entre tu API respuesta 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.

No permitir la selección de relleno en iOS

La regla más segura es simple. No trates al relleno como una opción real, incluso si la biblioteca de interfaz de usuario lo hace fácil de renderizar.

Un patrón práctico:

  • Usa un valor de sentinela vacío: Mantén el valor de relleno como '' o otro valor de aplicación inválido.
  • Valida antes de enviar: Rechaza el valor vacío en la validación de formularios, no solo en la interfaz de usuario.
  • Deshabilita las acciones de downstream: No habilites el botón de enviar hasta que exista un valor no de relleno.

Para flujos más estrictos, renderiza texto de ayuda cuando el relleno permanece 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. Aún así, necesitan etiquetas claras y un estado predecible.

Unos pocos hábitos dan sus frutos rápidamente:

  • Agregar etiquetas de accesibilidad: Hacer que el campo sea comprensible para los lectores de pantalla.
  • Mantener las etiquetas explícitas: “País” es mejor que “Seleccionar”.
  • Probar la restauración del estado: Re-abrir un formulario y confirmar que el elemento seleccionado anteriormente aparece correctamente.
  • Escribir pruebas unitarias alrededor de la lógica impulsada por la selección: La lógica fuera de la interfaz 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 para la empresa por sí solo. Los cambios de estado detrás de él suelen serlo.

Es el enfoque que mantiene las formas dinámicas estables. Trata al selector de NativeBase como una superficie de entrada. Coloca las reglas reales en tu flujo de estado, validación y envío.

Conclusiones

El selector de NativeBase sigue siendo útil cuando entiendes dónde se rompe. La configuración es sencilla, el estilo es manejable 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 selector frágil y la mueves a efectos impulsados por el estado, el componente se vuelve mucho más predecible.

Para los códigobases más antiguos, ese trabajo alrededor es a menudo suficiente. Para los 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 tu equipo envía Capacitor o aplicaciones Electron y quiere empujar arreglos de JavaScript, CSS, copia, configuración y recursos sin esperar a la revisión de la tienda Capgo es una buena opción. 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 la interfaz de usuario como las regresiones del selector escapen a la producción.

Actualizaciones en vivo para aplicaciones Capacitor con Capacitor

Cuando un bug en la capa web está activo, envíe la solución a través de Capgo en lugar de esperar días para la aprobación de la tienda de aplicaciones. Los usuarios obtienen la actualización en segundo plano mientras los cambios nativos siguen en el camino de revisión normal.

soporte humano de Martin

Comience ahora

Últimas noticias de nuestro Blog

Capgo le da las mejores perspectivas que necesita para crear una aplicación móvil verdaderamente profesional.