I’m having trouble with my React Native authentication screen and need some help.
I built a login form that shows a modal with a webview when users tap “forgot password”. Everything was working fine before, but now I keep getting a “null is not an object” error. The weird thing is that if I remove the WebViewModal component, the modal shows up without any problems. So I think the issue is somewhere in the WebViewModal setup.
Has anyone run into this before? I’m not sure what changed to break it.
import React, { useState, useRef } from 'react';
import {
Text, StyleSheet, View, TextInput,
TouchableOpacity, SafeAreaView, Modal,
KeyboardAvoidingView, ScrollView, Image
} from 'react-native';
import { CheckBox } from 'react-native-elements';
import { MaterialIcons } from '@expo/vector-icons';
import { useNavigation } from '@react-navigation/native';
import { Modalize } from 'react-native-modalize';
import WebViewModalProvider, { WebViewModal } from 'react-native-webview-modal';
const AuthScreen = () => {
const [passwordText, setPasswordText] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [rememberMe, setRememberMe] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const navigation = useNavigation();
const modalRef = useRef(null);
const openModal = () => {
modalRef.current?.open();
};
return (
<KeyboardAvoidingView style={styles.wrapper}>
<SafeAreaView>
<Modalize
ref={modalRef}
snapPoint={450}
>
<View style={{
flex: 1, height: 450,
flexDirection: 'column', alignItems: 'center'
}}>
<WebViewModalProvider>
<View style={{ padding: 20, height: 450 }}>
<SafeAreaView />
<WebViewModal
visible={true}
source={{ uri: "https://myapp.com/reset-password" }}
style={{ padding: 15 }}
/>
</View>
</WebViewModalProvider>
</View>
</Modalize>
<ScrollView style={{ flex: 1 }}>
<Image
source={require('../../images/brand-logo.png')}
style={styles.brandLogo}
/>
<Text style={styles.titleText}>
Welcome Back!
</Text>
<Text style={styles.subtitleText}>
Please sign in to continue
</Text>
<TextInput
style={styles.textField}
placeholder="Enter your email"
/>
<TextInput
style={styles.textField}
placeholder="Password"
value={passwordText}
onChangeText={(text) => setPasswordText(text)}
secureTextEntry={!showPassword}
/>
<TouchableOpacity
style={styles.eyeIcon}
onPress={() => setShowPassword(!showPassword)}
>
<MaterialIcons
name={showPassword ? 'visibility' : 'visibility-off'}
color="#00AA55"
size={24}
/>
</TouchableOpacity>
<View style={styles.optionsRow}>
<CheckBox
left
size={16}
checkedColor='#00AA55'
value={rememberMe}
checked={rememberMe}
onPress={() => setRememberMe(!rememberMe)}
containerStyle={{
backgroundColor: "transparent",
borderColor: "transparent"
}}
/>
<TouchableOpacity onPress={() => setRememberMe(true)}>
<Text style={styles.rememberText}>
Remember me
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={openModal}>
<Text style={styles.resetLink}>
Reset password
</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.submitButton}
onPress={() => navigation.navigate("MainTabs")}
>
<Text style={styles.submitText}>Sign In</Text>
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
wrapper: {
flex: 1,
backgroundColor: '#ffffff'
},
brandLogo: {
marginTop: 40,
marginBottom: 60,
width: 140,
height: 35
},
textField: {
marginTop: 25,
padding: 18,
height: 55,
width: 360,
borderColor: '#cccccc',
borderWidth: 1,
backgroundColor: '#fff',
fontSize: 15,
borderRadius: 12
},
submitButton: {
width: 340,
height: 55,
backgroundColor: '#333333',
marginTop: 30,
marginLeft: 10,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center'
},
submitText: {
fontSize: 16,
fontWeight: 'bold',
color: '#ffffff'
},
titleText: {
fontSize: 36,
fontWeight: 'bold',
color: '#000000',
marginBottom: 5
},
subtitleText: {
fontSize: 15,
marginTop: 8,
color: '#666666'
},
resetLink: {
textDecorationLine: 'underline',
fontWeight: 'bold',
marginTop: 12,
fontSize: 13,
marginLeft: 40
},
rememberText: {
textDecorationLine: 'underline',
fontWeight: 'bold',
marginTop: 12,
fontSize: 13,
marginRight: 60
},
optionsRow: {
marginTop: 20,
flexDirection: 'row'
},
eyeIcon: {
alignSelf: 'flex-end',
bottom: 38,
right: 35
}
});
export default AuthScreen;