あなたはここにいるのは、簡単なフィールドが簡単ではないはずです。キーボードが入力を隠している。iOSはAndroidとは異なるテキストをレンダリングしています。制御されたフィールドをクリアしても、ユーザーが見るものは常にクリアされない。基本的なログインフォームはデバッグセッションに変わります。
そのようなのは React NativeのTextInputの性質。モバイルアプリの最も使用されるコンポーネントの1つですが、レイアウト、ネイティブキーボードの動作、検証、アクセシビリティ、プラットフォーム固有のレンダリングの交差点に位置しています。チームは、ハッピーパスを迅速に学び、ドキュメントがほとんど言及していない粗いエッジに時間を費やすことになります。
このガイドは、実稼動環境で健全なパターンを取り巻くものに焦点を当てています。基本的なものもカバーしていますが、通常はQAが両プラットフォームでテストを開始した後に出現する未文書化のバグやエッジケースも含めています。チームがモバイルワークを場所を跨ぐように分割する決定を下している場合、 オフショア開発のためのTekRecruiterのガイド 入力重視の機能は、実装基準が明確でない場合に、実際に分解されるのはそのような作業です。より広範なアーキテクチャの背景については、この クロスプラットフォームモバイルアプリ開発ガイド は、近くに保管しておく価値があります。
目次
- コンテキスト:Capgoマーケティングウェブサイト。ロール:短いUIラベルまたはナビゲーションアイテム。ページ/エリア:blog/[slug].astro。メッセージキー`table_of_contents` (目次)。
- 実稼動チームが実際に必要とするもの
- 必須のTextInputパターンと例
- 制御されたコンポーネントと非制御されたコンポーネントの深い調査
- キーボードとフォーカスのハンドリングをマスターする
- キーボードとレイアウトの戦いを防ぐ
- 時が経つにつれてスタイルが良くなる
- iOS上でテキストが消える問題
モバイルフォームの基礎
すべてのモバイル製品はテキスト入力に依存しています。ログイン、サインアップ、検索、チェックアウト、プロフィール編集、サポートチケット、管理ツール、医療入力、フィールドオペスフォーム。すべてが同じ基本的なプリミティブに依存しています。
何が TextInput React Native 難しいのは、コンポーネントツリーで小さく見えますが、多くの責任を負っていることです。状態と同期し、ネイティブキーボードと協力し、iOSとAndroidで一貫した動作を示し、検証フィードバックを早く公開し、利用可能にする必要があります。どれか一つが崩れた場合、ユーザーはそれをすぐに感じます。
なぜこのコンポーネントが過度に痛みを与えるのか
破損したボタンは明らかです。破損したテキストフィールドは、ユーザーがタップ、タイプ、そしてアプリが信頼できることを想定するため、より微妙で悪いです。テキストが消失、フォーカスがジャンプ、キーボードがフィールドをブロックする場合、信頼は急速に低下します。
このコンポーネントはネイティブの動作に近い位置にあります。つまり、バグはReactの状態フロー、スタイリング、プラットフォームのデフォルト、またはネイティブイベントハンドリングから来る可能性があります。汚いJavaScriptを書いても、フィールドが2つのデバイスで異なる動作をすることになる可能性があります。
実用的なルール: 非凡でない入力をUIシステムとして扱う
実際のチームが必要とするもの
公式の例では初回レンダリングに到達します。実際の作業にはもっと必要があります。
- 予測可能な状態フロー: フィールドは、常にアプリケーションの状態を反映する必要があります。
- 信頼できる検証タイミング: エラーは、迷惑になるのではなく、役に立つときに表示されるべきです。
- プラットフォームの強靭性: iOSとAndroidは、意図的に同期する必要があります。
- デバッグ可能な動作: 何かが壊れたとき、修正はローカルで理解できるべきです。
なぜなら、ベストのチームは、入力パターンを標準化することで、早い段階で時間を節約できるからです。共有のラッパー、検証プロパティの命名規則、キーボードのルールの小さなセットは、後で起こりそうな大量の変化を防ぐのに役立ちます。
TextInputの基本とクイックリファレンス
A TextInput looks simple until it starts fighting the screen around it. One field can trigger stale state, keyboard oddities, autofill surprises, and platform-specific behavior that is not obvious from the prop list alone. Teams save time by standardizing the baseline API early.
デフォルトでは制御入力を使用してくださいが、どれが得られるか、どれがコストのかかるものかを知っておきましょう。制御されたフィールドは、レンダリングされた値を React の状態と結びつけるため、検証、リセット、プリフィールド、クロスフィールドのルールが予測可能になります。ただし、制御されたフィールドでは、すべてのキーストロークがレンダリングパスを通らなければなりません。したがって、低エンドのAndroidデバイスで実行する場合、各キーストロークごとに高価なフォーマットまたは検証ロジックが原因で遅延が生じる可能性があります。
常に使用するプロップ
ほとんどの生産的なフォームでは、基本的なセットアップは value, onChangeText、であり placeholderです。 これらの 3 つは一般的なパスをカバーしていますが、周囲のプロップは、フィールドがネイティブで感じられるか、フラストレーションを感じさせるかを決定します。
実装とバグのトリアージの際に参照する迅速なリファレンスです。
| プロップ | タイプ | 説明 |
|---|---|---|
value |
文字列 | 入力フィールドが表示する現在のテキストです。制御されたフィールドの場合、この値は常にコンポーネントの状態と一致する必要があります。 |
onChangeText |
関数 | 最新の文字列を受け取ります。ハンドラーは、特に長いフォームやリストでは、安価に保つようにしてください。 |
placeholder |
文字列 | 値が空の場合に表示されるヒントテキストです。ただし、ラベルとしてのみ頼るのは避けてください。 |
keyboardType |
文字列 | キーボードレイアウトを要求します。例えば、 email-address, number-pad、 phone-pad、実際のレイアウトはプラットフォームによって異なります。 |
secureTextEntry |
ブール値 | 入力されたテキストをマスクします。パスワードフィールドでは、Android上で選択と表示の切り替えがキーボードによって異なる場合に追加のテストが必要になることがよくあります。 |
autoCapitalize |
文字列 | ケースの挙動を制御します。 none を使用すると、メールアドレス、ユーザー名、コード、などが入力された値を厳密に保存することができます。 |
maxLength |
数字 | ネイティブレイヤーで入力長さを制限します。厳格な制限の場合、事後処理よりもこちらを優先してください。 |
multiline |
ブール値 | 複数行の入力を有効化します。高さ、垂直位置、送信動作はこの設定が有効になると変わります。 |
onFocus |
関数 | フィールドがフォーカスを取得したときに発火します。タッチ状態、分析、またはスクロールビューのロジックに役立ちます。 |
onBlur |
関数 | フォーカスがフィールドから離れたときに発火します。延期検証をトリガーするのに適しています。 |
returnKeyType |
文字列 | キーボードアクションのラベルを設定します。、、などを指定できます。iOSとAndroidのサポートは完全に一致しません。 next, donefunction searchFires when the field is changed. Useful for updating the model or triggering validation. |
onSubmitEditing |
関数 | キーボードの送信アクションが押されたときに実行される。複数行の組み合わせのいくつかは、開発者が期待するようにこのイベントを発生させない。 |
placeholderTextColor |
文字列 | プレースホルダーの色を設定します。プラットフォームのデフォルトが異なるため、対比を手動で確認してください。 |
editable |
ブール値 | 入力しながらフィールドをレイアウトに保持します。非活性のスタイリングはあなたの責任です。 |
いくつかのプロパティは、以下の点で混乱を招きます:
keyboardTypeヒントは保証ではありません。数値キーボードは、デバイスやロケールによって、記号を許可したり、負号を省略したりする可能性があります。maxLengthは、内部のスライスよりも安全です。制御されたフィールドでは、後処理がカーソルジャンプを引き起こす可能性があります。onChangeTextレイアウト以外の変更を含みます。Androidでは、テキストは、追加された後にのみ上寄せの配置に設定されます。multiline制御された例の最小限のセットtextAlignVertical="top".
__CAPGO_KEEP_0__
このパターンは覚えておくべき基本パターンです:
import React, { useState } from 'react';
import { TextInput, View, StyleSheet } from 'react-native';
export function EmailField() {
const [email, setEmail] = useState('');
return (
<View style={styles.container}>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email address"
keyboardType="email-address"
autoCapitalize="none"
style={styles.input}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 16,
},
input: {
borderWidth: 1,
borderColor: '#D0D5DD',
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 10,
},
});
これは機能しますが、生産環境ではcodeは通常、数種類のデフォルト値を追加します。Emailのようなフィールドの場合、 autoCorrect={false} キーボードの修正が値を意図せずに変更しないようにすることができます。複数の入力フィールドを持つフォームの場合、 returnKeyType="next" リファレンスを付けて早期に設定することで、後で焦点管理のクリーンアップを行う必要がなくなります。値を入力する際にフォーマットする場合、
物理デバイスで表示されるようになる選択肢のバグを最速で導入することになるため、制御されたフォーマットは非常に速い方法です。
もう一つの実用的ルールです。フィールドが検証、送信の準備、サーバーへのリハイドレーション、または条件付きUIに参加する場合、最初から制御されたフィールドを維持してください。
制御されていないフィールドに制御を後から追加することは、通常、焦点の喪失と状態の不一致のバグの始まりです。
基本的なTextInputパターンと例
import React, { useState } from 'react';
import { TextInput, StyleSheet } from 'react-native';
export function UsernameInput() {
const [username, setUsername] = useState('');
return (
<TextInput
value={username}
onChangeText={setUsername}
placeholder="Username or email"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
style={styles.input}
returnKeyType="next"
/>
);
}
const styles = StyleSheet.create({
input: {
borderWidth: 1,
borderColor: '#CCC',
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 10,
},
});
多くのバグは、さまざまな用途に適した一般的な入力実装を伸ばしすぎてしまっていることから生じています。Email、パスワード、コメント、フォーマットされた値は同じデフォルト値を必要としません。各パターンに必要なプロパティを与えましょう。 autoCapitalize="none" Emailまたはユーザー名入力 autoCorrect={false} 資格情報のようなものに使用します。キーボードはユーザーに助けますが、値を意図せずに変更しないようにします。
ユーザー名とEmailの場合も、安全なデフォルト値です。
import React, { useState } from 'react';
import { TextInput, View, Pressable, Text, StyleSheet } from 'react-native';
export function PasswordInput() {
const [password, setPassword] = useState('');
const [hidden, setHidden] = useState(true);
return (
<View style={styles.wrapper}>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry={hidden}
autoCapitalize="none"
autoCorrect={false}
style={styles.input}
returnKeyType="done"
/>
<Pressable onPress={() => setHidden(prev => !prev)} style={styles.toggle}>
<Text>{hidden ? 'Show' : 'Hide'}</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
wrapper: {
position: 'relative',
justifyContent: 'center',
},
input: {
borderWidth: 1,
borderColor: '#CCC',
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 10,
paddingRight: 60,
},
toggle: {
position: 'absolute',
right: 12,
},
});
{
"text": "
import React, { useState } from 'react';
import { TextInput, StyleSheet } from 'react-native';
export function NotesInput() {
const [notes, setNotes] = useState('');
return (
<TextInput
value={notes}
onChangeText={setNotes}
placeholder="Add notes"
multiline
textAlignVertical="top"
style={styles.textarea}
/>
);
}
const styles = StyleSheet.create({
textarea: {
borderWidth: 1,
borderColor: '#CCC',
borderRadius: 10,
paddingHorizontal: 12,
paddingVertical: 12,
minHeight: 120,
},
});
textAlignVertical="top" "
"
" TextInput " onChangeText "
"
"
- " "
- " 入力が破綻しているように感じる最速の方法の1つはカーソルがジャンプすることです。
- 検証はフォーマットとは独立して行う必要があります: 文字列は正しいように見えていても、ビジネスルールに違反する可能性があります。
入力コンポーネントは、ユーザーが入力した値、表示する値、サーバーが期待する値の3つの懸念を分離する必要があります。
制御されたコンポーネントと非制御されたコンポーネントの深掘り
フォームは通常、シンプルに始まります。製品は、入力欄内での検証、事前入力、入力が有効になるまでの送信ボタンの無効化、放棄されたステップの分析など、さまざまな要求を求め始めます。制御された入力と非制御された入力の選択は、どちらが痛みを与えるかを決定します。

制御された入力がデフォルトの理由
制御された TextInput 値を保持するReactの状態を保持します。値を valueに渡し、値を onChangeTextで更新します。利点は理論的ではありません。検証、条件付きレンダリング、送信の準備、フィールドのリセット、サーバーから推測された更新など、すべての操作は同じ真実の源から行われます。
const [email, setEmail] = useState('');
<TextInput
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
/>
このパターンも、実際のトレードオフを露呈しています。各キーストロークは、Reactの更新を引き起こします。小さなフォームでは、そのコストは微妙です。高価な兄弟レンダリングを持つ大きな画面では、低エンドのAndroidデバイスでは、可視的なタイピング遅延を引き起こす可能性があります。制御されたフィールドが遅いと感じる場合、その問題は通常、その周りのコンポーネントツリーではなく、自身ではありません。 TextInput itself. Memoize heavy children, keep form state local when possible, and avoid doing parsing, API calls, or schema validation directly inside onChangeText.
それを後から追加するのではなく。 制御されていない入力は、現在のテキストをnativeコンポーネント内に残し、refまたは送信時に出力します。そうした狭いツールですが、有効な用途があります。 適切な候補事項は次のとおりです。
捨てて使う検索フィールド:
画面は最終的なクエリまたはデバウンスアップデートのみに興味があります。
パフォーマンスの圧力の下で大きなフォーム:
- ユーザーが最後に送信する場合にのみ、すべてのフィールドをReactの状態に保つことは、無駄に費やされる可能性があります。 抛物検索フィールド:
- 画面は最終的なクエリまたはデバウンスアップデートのみに興味があります。 大きなフォームのパフォーマンスの圧力:ユーザーが最後に送信する場合にのみ、すべてのフィールドをReactの状態に保つことは、無駄に費やされる可能性があります。
- 第三者またはブリッジされたネイティブ入力: あるラッパーは制御されたプロパティよりも命令的なメソッドを自然に公開する。
value制御された入力は、公式の例では簡単に見えますが、実際には生産環境ではいくつかのエッジケースが頻繁に発生します。
バリデーションが高速化すると、フォームを送信した後はフォームをクリアすることが予測できないようになります。サーバーからのレスポンスをフィールドに反映することは、リフレッシュのプロパティと一時的な効果に変わります。
チームが実際に発生するバグ
制御された入力が簡単に見えると公式の例ではありますが、実際には生産環境ではいくつかのエッジケースが頻繁に発生します。
カーソルがフォーマット後にジャンプする。
フォーマットが文字列を毎回の入力で書き直すと、カーソルは最後に移動したり、予期せずに動き回ったりします。電話番号マスクやクレジットカードフォーマットは、通常の原因です。修正は、フォーマットを最小限に抑える、必要な場合に選択を保存する、またはカーソル状態を正しく扱うマスクライブラリを使用することです。 onChangeText Android上で重いレンダリング中に文字が落とされる。
制御されたフィールドにタイプすることが、親の再レンダリング、ネットワーク呼び出し、または同期バリデーションをトリガーすると、フィールドはキーストロークが欠けているように見えますが、実際の問題はレンダリングの圧力です。入力パスから費用の高い作業を移動してください。 制御されたモードと非制御モードの間で切り替える。
制御された入力は、公式の例では簡単に見えますが、実際には生産環境ではいくつかのエッジケースが頻繁に発生します。
フィールドが時々表示され、時々表示されない場合、動作が一貫しておらず、すぐに不整合になります。コンポーネントの生涯のために、1 つの所有権モデルを選択してください。フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。 value フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。 '' または undefined フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。 null フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。
フィールドが制御されている場合、__CAPGO_KEEP_0__ の代わりに __CAPGO_KEEP_1__ で初期化してください。フィールドが制御されていない場合、__CAPGO_KEEP_1__ の代わりに __CAPGO_KEEP_0__ で初期化してください。

キーボードとレイアウトの戦いを防ぐ
最初の修正は構造的なものです。画面の下部にフィールドが含まれている場合、関連する領域を KeyboardAvoidingView またはキーボード認識のスクロールコンテナで囲みます。キーボードがアクティブな入力を隠さないようにします。
実用的基準は次のようになります。
import React from 'react';
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
export function FormScreen({ children }) {
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
>
<ScrollView keyboardShouldPersistTaps="handled">
{children}
</ScrollView>
</KeyboardAvoidingView>
);
}
ヘッダー、タブバー、または固定フッターが含まれる画面では、スペースを各画面で調整する必要があります。1つのラッパーですべてのレイアウトを解決することはできません。
意図に基づいてフォーカスを移動する
リファレンスベースのフォーカス管理が、複数フィールドのフォームが smooth に感じられるようにするものです。ステップに合わせて returnKeyType を設定し、次のリファレンスにフォーカスを設定するように onSubmitEditing を接続します。
import React, { useRef, useState } from 'react';
import { TextInput, View } from 'react-native';
export function SignupFields() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const passwordRef = useRef<TextInput>(null);
return (
<View>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
returnKeyType="next"
onSubmitEditing={() => passwordRef.current?.focus()}
/>
<TextInput
ref={passwordRef}
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry
returnKeyType="done"
/>
</View>
);
}
これはまた onFocus と onBlur 使い方を学ぶことができる。多くのチームは、フォーカス時にボーダーカラーを変更する、エラー表示をブラー時に遅らせる、最後のフィールドが送信された後にキーボードを閉じるなど、標準的な動作を揃えるために努力しています。
視覚的なガイドが役立ちます。チームが動作の標準化に合意する場合、以下の例を参考にしてください。
実践から最終的なメモ。キーボードの閉じ方はフォーカスの動きよりも面倒なことが多いです。タップアウト外のフィールドは単純に思えるかもしれませんが、スクロールビューとボタンのインタラクションは混乱することがあります。実際のスクリーンに基づいて閉じ方の動作を構築し、孤立したストーリーブックスタイルの例ではありません。
スタイリング、アクセシビリティ、プラットフォームの差異
チームは通常、スタイリング、アクセシビリティ、プラットフォームの差異について別々に議論します。実際のアプリでは、つながっています。iOSで文字が短く表示され、スクリーンリーダーから目的がわからなくなるフィールドは完成していません。
使い古されないスタイル
使用 StyleSheet.create() 入力スタイルを長期にわたって使う場合に使用します。チームが標準化するために、ボーダー、パディング、ラジウス、プレースホルダー色、無効状態、エラーのバリアントを一つの場所で標準化することができます。インラインスタイルは実験用に問題ありませんが、設計システムが進化すると使い古されます。
使い続ける入力スタイルには通常以下の要素が含まれます。
- 一貫したタップエリア: パディングはフィールドをタップしやすくする必要があります。
- 可視化されたフォーカスとエラーの状態: ユーザーは、フィールドが有効または無効のときに明確なクイューが必要です。
- 予測可能なスペーシング: ラベル、ヘルパーテキスト、エラーはレイアウトにスペースが必要です。
入力の表面処理と視覚的階層を改善する際に、iOSのレンダリングの固有の特性を考慮する必要があるため、開発者はiOS固有の動作を考慮する必要があります。 React Nativeの線形グラデーションガイド iOS固有の動作とアクセシビリティ
クロスプラットフォームの統一性を確保するために、開発者はiOSのレンダリングの固有の特性を考慮する必要があります。
これは、Androidのデフォルトの動作と一致するように、文字列の末尾に省略記号を表示するようにします。 lineBreakStrategyIOSこのStack Overflowのスレッドでは、React Nativeのテキスト表示の動作について議論されています。 push-out このリファレンスは、入力エリアを囲むことで、iOSのレンダリングの固有の特性を考慮する必要があることを指摘しています。 iOSのレンダリングの固有の特性を考慮する必要があるため、開発者はiOS固有の動作を考慮する必要があります。.
iOSのレンダリングの固有の特性を考慮する必要があるため、開発者はiOS固有の動作を考慮する必要があります。 KeyboardAvoidingView または KeyboardAwareScrollView キーボードがフィールドを隠すリスクがある場合、そして bottomOffset 例えば 30 スペースの調整を異なる画面サイズで行うのに役立ちます。さらに、成熟したチームは、メンテナンスのために StyleSheet.create() を使用し、明確なラベル、ヘルパーテキスト、エラーメッセージを提供することを標準として扱うべきです。
実践的なチェックリストを使用して、レビューを実施します。
- フィールドを明確にラベル付けする: プレースホルダーテキストはラベルを完全に置き換えるものではありません。
- ヘルパーとエラーテキストを明示的に表示する: ユーザーは何が失敗したかを推測する必要がないようにします。
- iOSで長い値をテストする: Androidと異なる文字列の終端の可視性とトリミングの差異を考慮する必要があります。
- 向きの変更を確認する: レスポンシブなフォームレイアウトは、微妙に壊れることがあります。
良い携帯用入力では、テキストを受け入れるだけでなく、ユーザーに何が入るべきか、何が間違っているか、次に何が起こるかを伝える必要があります。
一般的なバグと高度な修正
大部分の時間は、このような問題に費やされます。問題が存在すること自体が悩みの種ではありません。多くの最悪の問題は、見た目は正しいように見えるパターンで発生するからです。

コントロールされたクリアリングのバグ
一番醜い問題の1つは、コントロールされた入力クリアリングのバグです。状態を空の文字列に設定し、フィールドをクリアすることを期待し、入力がフォーカスを維持しているのに、表示されたテキストが残ります。
この問題に関するコミュニティの議論では、標準的な方法である clear() または単純な状態の更新を使用して、ネイティブのイベントカウンタを回避し、レンダリングの不一致を引き起こすことが示されています。同様の議論では、この問題の唯一の信頼できるワークアラウンドとして、 key プロパティラッパーを強制するか、カスタム forceSetTextAndSelection コマンドを使用することを推奨しています。これは公式のAPIのパーツではありません。また、2024年から2025年のフォーラムの議論では、この問題は未解決のままです。 50を超える Stack OverflowのスレッドやRedditの投稿で問題を挙げている React Nativeコミュニティの制御入力クリアに関する議論.
最小限のワークアラウンドは次のようになります
import React, { useState } from 'react';
import { TextInput, View, Button } from 'react-native';
export function ClearableField() {
const [value, setValue] = useState('');
const [inputKey, setInputKey] = useState(0);
const clearField = () => {
setValue('');
setInputKey(prev => prev + 1);
};
return (
<View>
<TextInput
key={inputKey}
value={value}
onChangeText={setValue}
placeholder="Type something"
/>
<Button title="Clear" onPress={clearField} />
</View>
);
}
これは美しくないですが、信頼できる
iOSでのテキスト消失問題
iOSの表示不具合の別のカテゴリは、テキストが入力中に表示されなくなる、または長い値や特定のスタイルの組み合わせの場合に発生します
修正はデバッグのパスよりも簡単です
- 追加
flex: 1レイアウトが必要な場所に フレックス制約が欠けているとレンダリングが破綻する - Audit
selectionプロパティを慎重に: 不正な使用は視覚的な問題を引き起こす可能性があります。 - メモ化を戦略的に試してみてください: 親要素のレンダリングを安定させることで、グリッチの表面を減らすことができます。
- 使用してください
multiline={true}フィールドの動作に合致する場合にのみ使用してください: パッチとして機能する可能性がありますが、無条件に追加してはいけません。
生産環境でのデバッグでこれらの問題を早期にキャッチしたい場合は、 この React NativeとSentryを使用するためのガイド
UIのバグのフィードバックループを強化するために役立ちます。
多くの入力が再レンダリングされる場合のパフォーマンス
有効な戦術には、各フィールドに近い状態をローカライズすること、親画面がノイズが多い場合にフィールドラッパーをメモ化すること、そして高価な検証または検索駆動的なサイドエフェクトをデバウンスすることなどが含まれます。罠は、すべてのグローバル状態に早すぎると、タイプが粘着感があると感じることです。
タイプが遅延している場合、入力自体を非難する前に、各キーストロークごとに再レンダリングされる他のものを調べます。
統合とより広いエコシステム
TextInputはほとんどの場合、単独では存在しません。実稼働アプリケーションでは、フォームライブラリ、分析用のハック、検証レイヤー、API クライアント、デザインシステムの中にあります。そのエコシステムは重要です。なぜなら、チームが一貫性を保つことができる入力実装は、最良の入力実装だからです。
フォームライブラリとTextInputを使用する
FormikとReact Hook Formは両方ともnative TextInputとよく動作しますが、チームは異なる習慣に導かれます。Formikは、チームが制御された状態パターンを好む場合、明確で馴染みのあるものです。React Hook Formは、フォームが大きくなると再レンダリングオーバーヘッドを避けることができ、ボイラープレートを削減できます。
ライブ検証の場合、信号を有効に保ちましょう。タイプ中に高速かつローカルに検証し、blurまたはsubmitのときに重いチェックを予約してください。メールアドレス、ユーザー名、IDなどのレグエクスベースのルールは一般的ですが、チームがそのパターンをレビューする場合 Digital ToolPadのレグエクスガイド は、実稼働に送る前に式をテストするための実用的なリソースです。
native TextInputが十分である場合
NativeのTextInputは、チームがラベル、ヘルプテキスト、エラー状態、フォーカススタイルを持つ小さなラッパーコンポーネントを所有する場合、多くのアプリケーションでは十分です。
第三者コンポーネントライブラリは、多くの画面にわたる一貫したテーマ付けとプリビルドフォームプリミティブを必要とする場合に意味があります。代償は抽象化です。速度を得ますが、エッジケースをデバッグする際にライブラリ固有の動作も継承します。
iOSに関連する重要な注意事項があります。これはラッパー設計決定に影響を与えるからです。iOSのテキスト可視性の不具合のもう一つの未満された角度は、入力されたテキストが打鍵後に消え、特に長い値や特定のスタイリングの場合です。議論は次のStack Overflowのスレッドでまとめられています。 このスレッドでは、TextInputが入力されたテキストを表示しない問題について議論されています。 この問題の一般的な原因として、次のものが挙げられます。 flex: 1 と selection の不正なプロパティの使用が挙げられます。コミュニティの修正としては、入力をラッパー内に包んだり、 useMemo または multiline={true}を設定することが挙げられます。これらの修正は便利ですが、デフォルトのアーキテクチャにはなりません。
比較広いモバイルスタックを比較するチームや、ネイティブコンポーネントの動作がウェブ指向アプローチから離れ始めた場合、この comparison of React Native and Capacitor の比較は、有用なフレームワークの参考になります。
実践的な取り得は単純です。ネイティブのTextInputに厳格なラッパーを始め、設計システムと配信スピードが追加の抽象化を正当化するまで、ライブラリに移ります。
チームがモバイルアプリをWebベースのスタックで配信し、JavaScript、CSS、コピー、設定、資産の修正をストアレビューの待たずに安全にプッシュする必要がある場合 Capgo チームがこれに値する場合はチェックしてみてください。ライブラリは、UIの問題がフォームや入力フローの修正に迅速な修正が必要な場合に、制御されたライブアップデート、ロールアウトチャネル、ロールバック保護、リリースの可視性を提供します。