Forms in React Native
Formulieren in React Native werken anders dan in web React. Je gebruikt TextInput in plaats van <input>, en voor dropdowns gebruik je de @react-native-picker/picker package.
Belangrijk verschil met web:
- Geen
<form>tag in React Native - Gebruik
TextInputin plaats van<input> - Gebruik
onChangeTextin plaats vanonChange - Geen
event.preventDefault()nodig
TextInput Basics
De TextInput component is het belangrijkste element voor gebruikersinvoer.
Simpel Voorbeeld
import { useState } from 'react';
import { View, TextInput, Text, StyleSheet } from 'react-native';
export default function App() {
const [name, setName] = useState('');
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Typ je naam..."
value={name}
onChangeText={setName}
/>
<Text>Hallo {name}!</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
input: {
borderWidth: 1,
borderColor: '#ddd',
padding: 10,
borderRadius: 5,
fontSize: 16,
},
});
Belangrijke Props
<TextInput
placeholder="Email adres"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
secureTextEntry={false}
maxLength={50}
multiline={false}
numberOfLines={1}
/>
Keyboard Types:
default- Normaal toetsenbordemail-address- Email toetsenbord met @number-pad- Alleen nummers (geen decimalen)phone-pad- Telefoon toetsenbordnumeric- Nummers met +/- en decimaal
Meerdere Input Fields
Voor formulieren met meerdere velden gebruik je één useState met een object.
Contact Formulier
import { useState } from 'react';
import { View, TextInput, Pressable, Text, StyleSheet } from 'react-native';
export default function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleChange = (field, value) => {
setFormData({
...formData,
[field]: value,
});
};
const handleSubmit = () => {
console.log('Form data:', formData);
// Hier kun je data versturen naar een API
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Naam"
value={formData.name}
onChangeText={(text) => handleChange('name', text)}
/>
<TextInput
style={styles.input}
placeholder="Email"
value={formData.email}
onChangeText={(text) => handleChange('email', text)}
keyboardType="email-address"
autoCapitalize="none"
/>
<TextInput
style={[styles.input, styles.textArea]}
placeholder="Bericht"
value={formData.message}
onChangeText={(text) => handleChange('message', text)}
multiline
numberOfLines={4}
/>
<Pressable style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonText}>Verstuur</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
input: {
borderWidth: 1,
borderColor: '#ddd',
padding: 12,
borderRadius: 8,
marginBottom: 15,
fontSize: 16,
},
textArea: {
height: 100,
textAlignVertical: 'top',
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
alignItems: 'center',
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});
Pro tip: Gebruik textAlignVertical: 'top' bij multiline TextInput zodat tekst bovenaan begint!
Picker Component
Voor dropdown menu's gebruik je de @react-native-picker/picker package.
Installatie
npx expo install @react-native-picker/picker
Basis Gebruik
import { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { Picker } from '@react-native-picker/picker';
export default function App() {
const [selectedValue, setSelectedValue] = useState('');
return (
<View style={styles.container}>
<Text style={styles.label}>Kies een land:</Text>
<Picker
selectedValue={selectedValue}
onValueChange={(itemValue) => setSelectedValue(itemValue)}
style={styles.picker}
>
<Picker.Item label="Selecteer een land..." value="" />
<Picker.Item label="Nederland" value="nl" />
<Picker.Item label="België" value="be" />
<Picker.Item label="Duitsland" value="de" />
<Picker.Item label="Frankrijk" value="fr" />
</Picker>
<Text>Geselecteerd: {selectedValue}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
label: {
fontSize: 16,
marginBottom: 10,
},
picker: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
},
});
Picker in Formulier
const [formData, setFormData] = useState({
name: '',
country: '',
});
<Picker
selectedValue={formData.country}
onValueChange={(value) => setFormData({...formData, country: value})}
>
<Picker.Item label="Selecteer..." value="" />
<Picker.Item label="Nederland" value="nl" />
<Picker.Item label="België" value="be" />
</Picker>
ImagePicker - Afbeeldingen Selecteren
Met expo-image-picker kunnen gebruikers foto's selecteren uit hun galerij of met de camera maken.
Installatie
npx expo install expo-image-picker
Basis Gebruik
import { useState } from 'react';
import { View, Image, Pressable, Text, StyleSheet } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
export default function App() {
const [image, setImage] = useState(null);
const pickImage = async () => {
// Vraag permissie
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we hebben permissie nodig!');
return;
}
// Open galerij
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
setImage(result.assets[0].uri);
}
};
return (
<View style={styles.container}>
<Pressable style={styles.button} onPress={pickImage}>
<Text style={styles.buttonText}>Kies foto</Text>
</Pressable>
{image && (
<Image source={{ uri: image }} style={styles.image} />
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
},
image: {
width: 200,
height: 200,
marginTop: 20,
borderRadius: 8,
},
});
Camera Gebruiken
const takePhoto = async () => {
const { status } = await ImagePicker.requestCameraPermissionsAsync();
if (status !== 'granted') {
alert('Camera permissie nodig!');
return;
}
const result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled) {
setImage(result.assets[0].uri);
}
};
Let op: ImagePicker werkt niet in de web browser! Test altijd op je telefoon of emulator.
Form Validatie
Valideer formulierdata voordat je het verstuurt.
Simpele Validatie
import { useState } from 'react';
import { View, TextInput, Pressable, Text, Alert, StyleSheet } from 'react-native';
export default function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const validateEmail = (email) => {
return email.includes('@') && email.includes('.');
};
const handleSubmit = () => {
// Validatie
if (!email || !password) {
Alert.alert('Fout', 'Vul alle velden in');
return;
}
if (!validateEmail(email)) {
Alert.alert('Fout', 'Ongeldig email adres');
return;
}
if (password.length < 6) {
Alert.alert('Fout', 'Wachtwoord moet minimaal 6 karakters zijn');
return;
}
// Als alles OK is
console.log('Login met:', email, password);
Alert.alert('Success', 'Ingelogd!');
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholder="Wachtwoord"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
<Pressable style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonText}>Inloggen</Text>
</Pressable>
</View>
);
}
Volledig Voorbeeld - Profiel Formulier
import { useState } from 'react';
import { View, TextInput, Pressable, Text, Image, Alert, StyleSheet } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import * as ImagePicker from 'expo-image-picker';
export default function ProfileForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
country: '',
bio: '',
});
const [profileImage, setProfileImage] = useState(null);
const handleChange = (field, value) => {
setFormData({ ...formData, [field]: value });
};
const pickImage = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') return;
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [1, 1],
quality: 1,
});
if (!result.canceled) {
setProfileImage(result.assets[0].uri);
}
};
const handleSubmit = () => {
if (!formData.name || !formData.email || !formData.country) {
Alert.alert('Fout', 'Vul alle verplichte velden in');
return;
}
console.log('Profile data:', formData);
console.log('Image:', profileImage);
Alert.alert('Success', 'Profiel opgeslagen!');
};
return (
<View style={styles.container}>
<Text style={styles.title}>Profiel Bewerken</Text>
{/* Profile Image */}
<Pressable onPress={pickImage} style={styles.imageContainer}>
{profileImage ? (
<Image source={{ uri: profileImage }} style={styles.image} />
) : (
<View style={styles.imagePlaceholder}>
<Text>Kies foto</Text>
</View>
)}
</Pressable>
{/* Name */}
<TextInput
style={styles.input}
placeholder="Naam *"
value={formData.name}
onChangeText={(text) => handleChange('name', text)}
/>
{/* Email */}
<TextInput
style={styles.input}
placeholder="Email *"
value={formData.email}
onChangeText={(text) => handleChange('email', text)}
keyboardType="email-address"
autoCapitalize="none"
/>
{/* Country Picker */}
<View style={styles.pickerContainer}>
<Picker
selectedValue={formData.country}
onValueChange={(value) => handleChange('country', value)}
>
<Picker.Item label="Selecteer land *" value="" />
<Picker.Item label="Nederland" value="nl" />
<Picker.Item label="België" value="be" />
<Picker.Item label="Duitsland" value="de" />
</Picker>
</View>
{/* Bio */}
<TextInput
style={[styles.input, styles.textArea]}
placeholder="Bio"
value={formData.bio}
onChangeText={(text) => handleChange('bio', text)}
multiline
numberOfLines={4}
/>
{/* Submit Button */}
<Pressable style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonText}>Opslaan</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
imageContainer: {
alignItems: 'center',
marginBottom: 20,
},
image: {
width: 120,
height: 120,
borderRadius: 60,
},
imagePlaceholder: {
width: 120,
height: 120,
borderRadius: 60,
backgroundColor: '#ddd',
justifyContent: 'center',
alignItems: 'center',
},
input: {
borderWidth: 1,
borderColor: '#ddd',
padding: 12,
borderRadius: 8,
marginBottom: 15,
backgroundColor: 'white',
fontSize: 16,
},
pickerContainer: {
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
marginBottom: 15,
backgroundColor: 'white',
},
textArea: {
height: 100,
textAlignVertical: 'top',
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
alignItems: 'center',
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});
Samenvatting
TextInput
Gebruik onChangeText, niet onChange
Picker
Dropdown menu's met @react-native-picker/picker
ImagePicker
Foto's selecteren met expo-image-picker
Validatie
Check data voordat je submit
Je hebt nu geleerd:
- TextInput gebruiken voor text invoer
- Meerdere input fields beheren met één state object
- Picker gebruiken voor dropdown menu's
- ImagePicker voor foto selectie en camera
- Form validatie voordat je data verstuurt
- Complete profiel formulier implementeren