Eingabe mit TextInput
Dauer: 30 Minuten
TextInputfür neue Todos einbinden
TextInput für neue Todos einbinden
Mit TextInput gibt es in
React Native eine Komponente für die Eingabe von Text. Wir bauen eine
neue Komponente AddTodo, die ein TextInput und einen Button
enthält, um ein neues Todo hinzuzufügen. Durch das Antippen des
Buttons wird das Eingabefeld TextInput angezeigt.
Folgende Komponente in components/AddTodo.jsx erstellen:
import { useState } from 'react';
import { Button, StyleSheet, TextInput, View } from 'react-native';
export default function AddTodo() {
const [inEditMode, setEditMode] = useState(false);
return (
<View style={{ marginVertical: 20, width: '80%' }}>
{inEditMode ? (
<TextInput
style={styles.input}
autoFocus
placeholder="Neues Todo eingeben"
returnKeyType="done"
onSubmitEditing={() => {
// TODO 😉: Todo hinzufügen…
setEditMode(false); // Eingabemodus verlassen
}}
onBlur={() => setEditMode(false)} // Abbrechen bei Fokusverlust
/>
) : (
<Button
title="Todo hinzufügen"
onPress={() => setEditMode(true)}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
input: {
height: 40,
borderColor: 'lightgray',
borderRadius: 5,
borderWidth: 1,
padding: 10,
},
});Die Props autoFocus und placeholder im TextInput sorgen dafür,
dass das Eingabefeld automatisch fokussiert wird bzw. dass ein grauer
Hinweistext erscheint, wenn das Eingabefeld leer ist. Mit returnKeyType="done"
wird die Eingabetaste der Tastatur als „Fertig“ (ggf. als Checkbox)”
angezeigt.
onSubmitEditing wird aufgerufen, wenn die Eingabetaste gedrückt
wird, und onBlur, wenn das Eingabefeld den Fokus verliert (z.B.
durch Antippen außerhalb des Eingabefelds).
TextInput ist in der Regel eine kontrollierte Komponente, d.h.
der eingegebene Text wird in einem state gespeichert, um z.B.
Live-Validierungen durchzuführen oder den Text anderweitig zu
verwenden. Wir verwenden in unserem einfachen Beispiel TextInput
als unkontrollierte Komponente, d.h. der eingegebene Text wird nicht
in einem state gespeichert.
TextInput hat viele weitere nützliche Props, siehe
https://reactnative.dev/docs/textinput#props
DerUmgang mit dem state sollten an dieser Stelle gut
nachvollziehbar sein:
- Button antippen zeigt das
TextInputan mitsetEditMode(true) - Das
TextInputhat zwei Möglichkeiten, den Eingabemodus zu verlassen:- Eingabetaste (Fertig) drücken (
onSubmitEditingmitsetEditMode(false)) - Fokus verlieren (Antippen außerhalb des Eingabefelds mit
onBlurundsetEditMode(false))
- Eingabetaste (Fertig) drücken (
Die Styles sorgen dafür, dass das Eingabefeld gut sichtbar und nutzbar ist, indem es etwas größer ist und einen grauen Rand hat.
Wir müssen uns noch darum kümmern, dass in onSubmitEditing das neue
Todo tatsächlich hinzugefügt wird. Dies erledigen wir im nächsten
Schritt.
AddTodo in App einbinden
Wir stellen AddTodo in App.js oberhalb der Todo-Liste dar,
weil dies die einfachste Lösung ist. Sollte AddTodo am
unteren Bildschirmrand dargestellt werden, dann wird die Tastatur
möglicherweise die Eingabe verdecken (hierzu gibt es z.B. mit
KeyboardAvoidingView
Lösungen, die aber den Rahmen dieses Workshops
sprengen).
Folgende Änderungen sind nötig:
// App.js: AddTodo importieren
import AddTodo from './components/AddTodo';
// Rest bleibt gleich
export default function App() {
return (
<SafeAreaView style={styles.container}>
<AddTodo />
<TodoList todos={todos} />
<StatusBar style="auto" />
</SafeAreaView>
);
}
// Styles bleiben gleichTodo der Liste hinzufügen
Die TodoListe wird nun um die Möglichkeit erweitert, ein neues Todo
hinzuzufügen, d.h. die Todos müssen in einem state verwaltet werden.
Wir gehen wie folgt vor in App.jsx vor:
useStateimportieren- das Array
todosindataumbenennen, weil wir den Namentodosgleich an anderer Stelle benötigen - Einen Zustand
todosmitdatainitialisieren
import React, { useState } from 'react';
// Rest bleibt gleich
const data = [
{ id: 1, text: 'Einkaufen' },
{ id: 2, text: 'Sport' },
{ id: 3, text: 'React Native lernen' },
];
export default function App() {
const [todos, setTodos] = useState(data);
export default function App() {
return (
<SafeAreaView style={styles.container}>
<AddTodo />
<TodoList todos={todos} />
<StatusBar style="auto" />
</SafeAreaView>
);
}
// Styles bleiben gleich
}Nun müssen wir AddTodo mitteilen, wie ein neues Todo hinzugefügt
werden soll. Hierzu übergeben wir eine Funktion als Prop onAddTodo
an AddTodo, die mit dem neuen Todo-Text aufgerufen wird:
// Rest bleibt gleich
export default function App() {
const [todos, setTodos] = useState(data);
export default function App() {
return (
<SafeAreaView style={styles.container}>
<AddTodo
onAddTodo={(text) => {
if (!text || !text.trim()) return; // leere ignorieren
const newTodo = {
id: todos.length + 1,
text: text,
};
setTodos([...todos, newTodo]);
}}
{/* usw. */}
)
}} />Das neue Todo wird nur hinzugefügt, wenn der Text nicht leer ist
(ggf. nur aus Leerzeichen besteht). Ein neues Todo-Objekt wird
erstellt mit einer neuen ID (einfach die Länge des Arrays + 1)
und dem übergebenen Text. Mit setTodos wird der Zustand todos
aktualisiert, indem ein neues Array mit dem neuen Todo am Ende
erstellt wird (... ist der Spread-Operator in JavaScript).
Nun fehlt nur noch die Verwendung des onAddTodo-Props in AddTodo:
// Rest bleibt gleich
export default function AddTodo({ onAddTodo }) {
const [inEditMode, setEditMode] = useState(false);
return (
<View style={{ marginVertical: 20, width: '80%' }}>
{inEditMode ? (
<TextInput
style={styles.input}
autoFocus
placeholder="Neues Todo eingeben"
returnKeyType="done"
onSubmitEditing={({ nativeEvent: { text } }) => {
const value = text.trim();
if (!value) return; // leere ignorieren
onAddTodo(value);
setEditMode(false);
}}
onBlur={() => setEditMode(false)} // Abbrechen bei Fokusverlust
/>
) : (
<Button
title="Todo hinzufügen"
onPress={() => setEditMode(true)}
/>
)}
</View>
);
}
// Styles bleiben gleichIn onSubmitEditing wird der eingegebene Text aus dem Event-Objekt
entnommen (nativeEvent.text), getrimmt und geprüft, ob er leer ist. Wenn
der Text nicht leer ist, wird die onAddTodo-Funktion mit dem
Text aufgerufen, um das neue Todo hinzuzufügen.
In React Native kommt es häufig vor, dass wir einen state in
einem Eltern-Element verwalten und diesen dann an ein Kind-Element
übergeben. Das Kind-Element kann dann den state nicht verändern,
sondern muss den Eltern-Element mitteilen, dass sich etwas geändert hat.
Dies geschieht über eine Funktion, die wir dem Kind-Element als Prop übergeben
(siehe oben im onAddTodo-Prop).