Eingabe mit TextInput
Dauer: 30 Minuten
TextInput
fü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
TextInput
an mitsetEditMode(true)
- Das
TextInput
hat zwei Möglichkeiten, den Eingabemodus zu verlassen:- Eingabetaste (Fertig) drücken (
onSubmitEditing
mitsetEditMode(false)
) - Fokus verlieren (Antippen außerhalb des Eingabefelds mit
onBlur
undsetEditMode(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 gleich
Todo 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:
useState
importieren- das Array
todos
indata
umbenennen, weil wir den Namentodos
gleich an anderer Stelle benötigen - Einen Zustand
todos
mitdata
initialisieren
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 gleich
In 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).