React Native の NativeBase ピッカーでよく遭遇する壁に当たったことはありませんか。 ドロップダウンが表示され、iOS で機能するのに対し、アンドロイドはビジネスロジックが実行されないままピッカーが表示されます。 onValueChange __CAPGO_KEEP_0__
NativeBase ピッカーのそのギャップは、経験豊富な開発者を意識せずに捕まえる。セットアップは簡単、スタイリングは管理可能ですが、生産性の安定性は、Android固有のエラーを理解することによってのみ実現されます。Android固有のエラーは、ほとんどのガイドでは省略または言及されていません。
目次
- NativeBase ピッカーの使用を開始する
- State と選択のハンドリング
- Android の onValueChange バグのトラブルシューティング
- NativeBase ピッカーのスタイリングとテーマ設定
- 高度なシナリオとベストプラクティス
- まとめ
NativeBase ピッカーの使用開始
ピッカーは通常、スプリントの後半に追加されるコンポーネントです。国選択、ステータスフィールド、アポイントメントタイプ、発送オプション。プラットフォームの動作がUIに漏れ出すまで、感じるのは小さなものです。
良いニュースは NativeBase ピッカー 画面上に表示されるのは簡単です。iOSとAndroidでネイティブのピッカーをレンダリングし、古いNativeBaseのセットアップで非推奨のReact Native Pickerを置き換えるように設計されています。なぜなら、多くのレガシーコードベースはそれに依存しているからです。

通常のReact Native環境にコンポーネントをインストールします。
NativeBaseをすでに使用しているプロジェクトの場合、主なタスクは、必要な基本的な要素をインポートし、初日から不要なラッパーロジックを避けることです。最もシンプルな可視ピッカーから始めましょう。
If you’re working across mobile and hybrid stacks, it also helps to understand how React code gets packaged in broader environments like React NativeアプリケーションのワークフローでCapacitorが使用されている場合、ピッカーは馴染みのあるものですが、展開の期待は変わります。. The picker code stays familiar, but deployment expectations change.
抽象化なしで最初のピッカーをレンダリングします。
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>
);
}
最初のパスでは、次の2つの質問に答える必要があります。
正しくレンダリングされるかどうか:
- フィールドがレイアウト内に表示され、スペースを尊重し、両方のプラットフォームで開くかどうかを確認したいです。 __CAPGO_KEEP_0__
- インポートパスが正しいですか: NativeBaseプロジェクトは、古いコンポーネントAPIと新しいコンポーネントAPIを混在させたことによる、面倒な理由で失敗することがよくあります。
- 選択された値が制御されているか: 即興のプロトタイプでも、stateから値を取得するようにしてください。
selectedValuefrom state. Uncontrolled picker code becomes harder to debug later.
実用的なルール: まず、サーバーからデータ、プレースホルダー規則、アナリティクスハック、バリデーションをすべて同じピッカーにマッピングしないでください。まずコンポーネントを表示し、制御するようにしてください。
最小限の基準は重要です。Androidが後で不正行為を始めたら、問題はフォームアーキテクチャ全体ではなく、ピッカーだけです。
Stateのバインディングと選択の処理
ピッカーがレンダリングされたら、次の仕事はそれを有用にすることです。React Nativeでは、それを制御された入力として扱い、選択された値をコンポーネントのstateに保持することです。
標準的なパスは簡単です。現在の値を保存し、 useState値を渡します。 selectedValue、状態を更新し onValueChangeこのアプローチは、他のフォームフィールドの場合と同様に、 React Native TextInput のパターンUI コントロールが異なっても
使用する値を制御する
ここでは、検証や副作用を追加する前に、以下のようなシンプルなコードを使用します。
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>
</>
);
}
code は、予測可能な真実の源を提供します。UI は role、そして、すべての下流の関数は同じ状態から読み取る
選択ロジックを小さくし、テスト可能に
開発者がオーバーロードすると、問題が生じることが多い onValueChange。データを取得し、複数の状態スライスを変更し、ナビゲーションをトリガーし、分析をログするinline関数を使用する
UI コントロールが異なっても、
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>
</>
);
}
この構造体は、2つの便利な機能を実行します:
- 選択状態の更新のみを担当するようにピッカーを設定します。
- アプリの動作を
useEffectに移します。ここでは、テストや推論を行うことができます。
フォームコンポーネントが、選択された値を信頼できるようにアプリに伝えることができない場合、すべての副作用が疑問視されます。
Androidでは、このNativeBaseピッカーの意図されたイベントフローが常に機能しないことがあります。
AndroidのonValueChangeバグのトラブルシューティング
この部分は、ほとんどの記事が省略しています。NativeBaseピッカーはAndroid上で正常に表示されるかもしれませんが、必要な時には機能しないことがあります。
コミュニティドキュメントでは、古いピッカー実装に関するクロスプラットフォームの分割について説明しています。 Androidでは、 onValueChangeにアタッチされたカスタム関数をトリガーしないのに対し、iOSではをトリガーし、機能しないことが説明されています Android上で100%の機能不具合が発生し、Androidデバイスで0%の成功率で機能トリガーが発生するにもかかわらず、同様のcode実装 文書化されたレポートに記載されているものと同じです。同様のドキュメントは開発者にワークアラウンドまたは移行を指示し、NativeBase 3.0 Select コンポーネントが 98%の機能トリガー成功率を両方のプラットフォームでテスト環境で達成 比較検討の際に、NativeBase ピッカー ドキュメントと移行コンテキスト NativeBase ピッカー コンポーネントのAndroid上の一般的なバグとその提案された解決策を示すインフォグラフィック.

実装の詳細が原因です。Android上のNativeBase ピッカーはnative スピナーに依存し、そのレイヤーは、多くの開発者が期待するように、ラッパーにイベントリスナーを伝播しません。iOS上では、モーダルベースの動作はイベントシステムに正しく結合されます。
このバグはなぜデリケートに感じるのか
UIが見えます。オプションを開くことができます。選択可能なアイテムを選択することもできます。ですが、ビジネス関数は実行されません。
失敗する典型的なパターンは次のようになります
<Picker
selectedValue={status}
onValueChange={(value) => {
setStatus(value);
saveStatusToApi(value);
trackSelection(value);
updateDependentFields(value);
}}
>
iOS上では、意図どおりに動作するかもしれません。Android上では、ピッカーはレンダリングされますが、関数は実行されません。
Aプロダクションで機能するワークアラウンド
最も信頼できるワークアラウンドは、外観ではなく、構造的なものです。ピッカーのインタラクションは、選択された値を保存することに焦点を当て、ピッカーハンドラーの外側の状態の変更に反応します。
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>
);
}
なぜこれが役立つか
- 状態は中央にあります コンポーネントロジックは
status、ピッカーイベントペイロードだけではありません。 - 副作用は明確になります APIコール、依存フィールドの更新、トラッキングは、脆弱なUIコールバック内に存在しなくなります。
- codeを置き換えることが容易になります NativeBaseピッカーから移行する場合、ビジネスロジックの大部分が変更されずに残ります。
Android重視のプロジェクトの場合、また、既存のアプリがネイティブパッケージングの複雑さを持つ場合、実機でテストすることをお勧めします。 Android用のCapacitorアプリのセットアップ.
Select への移行は、より綺麗な決定です。
ピッカーがチェックアウト、オンボーディング、または規制されたデータ入力などの重要なワークフロー内に位置している場合、古い動作を修正する代わりに、NativeBase 3.0 への移行が長期的にはより安全な選択肢となる場合があります。 Select バグは単に不便なだけでなく、ビジネスロジックを安全に配置できる場所を変更します。
古いピッカーを維持する場合は、それをUIシェルとして最小限の責任を持たせるようにしてください。この考え方は、静かにAndroidのバグを防ぐのに役立ちます。
ピッカー コンポーネントのスタイリングとテーミング
機能するピッカーでも、他のアプリと一致しないと未完成のように見えます。NativeBase は、コントロールが意図的に感じられるように十分なハックを提供しますが、最もきれいな結果は、ピッカーを直接戦うのではなく、コントロールの周囲のコンテナをスタイリングすることによって得られます。
スマートフォンを握った手が、旅行予約アプリのNativeBase ピッカー ドロップダウン メニューを表示している。

ピッカー自体は、部分的にネイティブレンダリングによって制限されています。コンテナは、ピッカーの周囲のスペース、境界処理、レイアウトリズムの制御を提供します。
実用的パターン:
このアプローチは、テーマのオーバーライドを過度にエンジニアリングすることなく、ほとんどの場合に目的を達成することができます。
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,
},
});
That approach usually gets you most of the way there without over-engineering theme overrides.
プラットフォームに合わせた表示を使用する
iOSとAndroidはほとんど同じスタイリングが必要ではない。 一貫した意図が必要である。 同じ視覚的トークンは、まだ異なるパディング、アイコンの配置、またはピッカー モードが必要である。
有用な調整には含まれる
- iOSの場合: フィールドに空間を与え、モーダル表示が周囲のラベルとどのように関係しているかを注意する
- Androidの場合: テキストのクリッピングとデフォルトのスピナー高さを複数のデバイスで確認する
- 両方の場合: プレースホルダーテキストを実際の選択と視覚的に区別する
短い比較が役に立つ:
| 懸念 | iOS | Android |
|---|---|---|
| オープンベHAVIOR | モーダルフィール | スピナーフィール |
| アイコンの期待 | しばしば装飾的な | しばしば機能的な |
| スペーシングの問題 | プレースホルダーライアウトがゆるい | テキストがぎこちなく感じる |
UIにグラデーション、レイヤードカード、または高コントラストの表面が含まれている場合、ピッカーのラッパーを、インターフェイスの他の部分で使用されている同じ処理と同様に揃えます。 React Nativeの線形グラデーションUIワークのパターンと同様に.
設計ノート: ユーザーは、ドロップダウン自体よりも、フォーム内で閉じたフィールドがどのように収まるかでピッカーを評価します。
したがって、ボーダーライアス、ラベルスペーシング、プレースホルダーカラーは、エキゾチックなピッカーのカスタマイズよりも重要です。
高度なシナリオとベストプラクティス
ほとんどのピッカーのバグは、コンポーネントがプロトタイプフェーズを超えた後に出現します。問題は、オプションがサーバーから取得され、バリデーションルールがプラットフォームによって異なり、プレースホルダーアクションが有効な値として振る舞えない場合に始まります。
iOS上で特に悩ましいエッジケースが繰り返し発生しています。開発者は、プレースホルダーエントリが選択可能になるのを防ぎながら、サーバーからピッカー値をロードする必要がありますが、公式のマテリアルはそのパスを直接扱っていません。コミュニティの議論は、 プレースホルダーアイテムがiOS上で選択可能であることを示しています。これは、実際のアプリケーションで不一致の動作が生じる原因となり、サーバーからロードされたピッカー値とプレースホルダーセレクションに関するこの React Nativeコミュニティの議論を参照してください。.

サーバーからピッカーのオプションを安全にロードする
最もよく見られる間違いは、取得したデータを即座にピッカー用に準備したと考えることです。API の応答とコンポーネントの間には、小さな変換層を維持してください。
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>
);
}
フォーマットのこのステップは、安定した契約を与えます。ピッカーは、APIの内部構造を知る必要がありません。
iOS上のプレースホルダーの選択を防ぐ
最も安全なルールは単純です。プレースホルダを実際のオプションとして扱わないでください。UIライブラリがそれを簡単にレンダリングできるようにしても。
実践的なパターン:
- 空のシーケンス値を使用します: プレースホルダーの値を
''または別の無効なアプリケーション値として保持します。 - 入力検証する: 空の値をフォーム検証で拒否し、UIだけではありません。
- 下流のアクションを無効化します: プレースホルダーの値が選択されている限り、サブミットボタンを有効にしないでください。
厳格なフローでは、プレースホルダーの値が選択されている場合にヘルプテキストをレンダリングします:
const isValidSelection = selectedCategory !== '';
Then、アクションボタンをゲートするか、APIの呼び出しをその条件に置き換えましょう。
アクセシビリティと実稼働の慣習
ピッカーは、ネイティブの見た目でアクセシビリティのレビューを通過することがよくありますが、明確なラベルと予測可能な状態が必要です。
いくつかの慣習がすぐに効果を発揮します:
- アクセシビリティのラベルを追加する: スクリーンリーダーでフィールドを理解できるようにする:
- ラベルを明確にする: 「国」は「選択」よりも良いです。
- 状態の復元をテストする: フォームを再開し、以前選択されたアイテムが正しく表示されることを確認する:
- 選択に基づくロジックのユニットテストを書く: ロジックはUI外側で最も重要です、 単位テストのReactの動作 状態の移行を保護するのに役立ちます。
ピッカー自体はあまりビジネスクリティカルではありません。通常は、その背後にある状態の変更がビジネスクリティカルです。
動的フォームを安定させるには、動的フォームを安定させるための考え方が必要です。NativeBaseピッカーを入力面として扱い、実際のルールは状態、検証、送信フローに置きます。
結論
NativeBaseピッカーは、破綻を理解している場合にまだ役立ちます。セットアップは簡単、スタイリングは可能、サーバーからドライブされたオプションリストは管理可能です。Androidのイベントハンドリングが大きな罠です。フラグレートなピッカーのコールバックからビジネスロジックを取り除き、状態駆動のエフェクトに移すと、コンポーネントは予測可能になります。
古いコードベースの場合、代替手段はよく機能します。重要なフローでは、NativeBaseピッカーから Select は通常、より良い投資です。どちらの場合も、同じ鍵があります。ピッカーを信頼しないでください。なぜなら、ピッカーはレンダリングされますから。
If your team ships Capacitor or Electron apps and wants to push JavaScript, CSS, copy, config, and asset fixes without waiting for store review, Capgo は見る価値があります。Capgoは、UIのバグのようなピッカーの後退を生産環境に逃すことができるように、署名のライブアップデート、ロールアウトの制御、ロールバックの保護、リリースの可視性を提供します。