I don't know why only on IOS emulator keyboard is not showing But on android it's working fine. I am trying to take user input for authentication and sending the data to the real-time database firebase.
import React, { useState, useReducer, useEffect, useCallback } from "react";
import {
KeyboardAvoidingView,
ScrollView,
View,
Button,
StyleSheet,
ActivityIndicator,
Alert,
} from "react-native";
import { useDispatch } from "react-redux";
import Input from "../../components/UI/Input";
import Card from "../../components/UI/Card";
import Colors from "../../constants/Colors";
import * as authActions from "../../store/actions/Auth";
const FORM_INPUT_UPDATE = "FORM_INPUT_UPDATE";
const formReducer = (state, action) => {
if (action.type === FORM_INPUT_UPDATE) {
const updatedValues = {
...state.inputValues,
[action.input]: action.value,
};
const updatedValidities = {
...state.inputValidities,
[action.input]: action.isValid,
};
let updatedIsFormValid = true;
for (const key in updatedIsFormValid) {
updatedIsFormValid = updatedIsFormValid && updatedValidities[key];
}
return {
formIsValid: updatedIsFormValid,
inputValidities: updatedValidities,
inputValues: updatedValues,
};
}
return state;
};
const AuthenticationScreen = (props) => {
const [Isloading, setIsloading] = useState(false);
const [error, setError] = useState();
const [IsSignup, setIsSignup] = useState(false);
const dispatch = useDispatch();
const [formState, dispatchFormState] = useReducer(formReducer, {
inputValues: {
email: "",
password: "",
},
inputValidities: {
email: false,
password: false,
},
formIsValid: false,
});
const authHandler = async () => {
let action;
if (IsSignup) {
action = authActions.signup(
formState.inputValues.email,
formState.inputValues.password
);
} else {
action = authActions.login(
formState.inputValues.email,
formState.inputValues.password
);
}
setError(null);
setIsloading(true);
try {
await dispatch(action);
props.navigation.navigate("Shop");
} catch (error) {
setError(error.message);
setIsloading(false);
}
};
useEffect(() => {
if (error) {
Alert.alert("An error occurred ", error, [{ text: "Okay" }]);
}
}, [error]);
const inputChangeHandler = useCallback(
(inputIdentifier, inputValues, inputValidities) => {
dispatchFormState({
type: FORM_INPUT_UPDATE,
value: inputValues,
isValid: inputValidities,
input: inputIdentifier,
});
},
[dispatchFormState]
);
return (
<KeyboardAvoidingView
behaviour="padding"
keyboardVerticalOffset={50}
style={styles.screen}
>
<Card style={styles.auth}>
<ScrollView>
<Input
id="email"
label="E-mail"
keyboardType="email-address"
required
email
autoCapitalize="none"
warningText="Please enter valid Email Address"
onInputChange={inputChangeHandler}
intialValue=""
/>
<Input
id="password"
label="Password"
keyboardType="default"
secureTextEntry
required
minLength={5}
autoCapitalize="none"
warningText="Please enter valid Password"
onInputChange={inputChangeHandler}
intialValue=""
/>
<View style={styles.buttonContainer}>
<View style={styles.button}>
{Isloading ? (
<ActivityIndicator size="large" color={Colors.primary} />
) : (
<Button
title={IsSignup ? "Sign up" : "Login"}
color={Colors.primary}
onPress={authHandler}
/>
)}
</View>
<View style={styles.button}>
<Button
title={`Switch to ${IsSignup ? "Login" : "Sign Up"}`}
color={Colors.secondary}
onPress={() => {
setIsSignup((prevState) => !prevState);
}}
/>
</View>
</View>
</ScrollView>
</Card>
</KeyboardAvoidingView>
);
};
AuthenticationScreen.navigationOptions = {
headerTitle: "Authenticate",
};
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
auth: {
width: "80%",
maxWidth: 400,
maxWidth: 400,
padding: 20,
},
buttonContainer: {
marginTop: 20,
},
button: {
margin: 5,
},
});
export default AuthenticationScreen;
I can only be able to type email and password with my laptop keyboard and I have tried clicking on both fields to check whether the keyboard in the IOS emulator popup or not.
The keyboard is working fine on the android emulator.
The simulator detects that you have an external keyboard available and thus doesn't show the software keyboard. You can disable this behaviour using I/O -> Keyboard -> Connect Hardware Keyboard. Or you can Command + K to toggle the Software Keyboard manually.
Related
I am implementing a provider which helps me to have the state of my user in different views, the main function of this provider is to render different one or the other stack navigator depending on whether the variable is full or empty, this in order to be able to generate two groups of screens depending on whether the user is authenticated or not.
Here my code:
View router.tsx:
import { NavigationContainer } from "#react-navigation/native"
import React, { useContext, useEffect, useState, useRef } from "react"
import { UserContext } from "./context/Usuario"
import AuthStack from "./routes/AuthStack"
import GeneralStack from "./routes/GeneralStack"
const Router = () => {
const { me } = useContext(UserContext)
const auth = useRef(false)
useEffect(() => {
return () => {
auth.current = me !== null
console.log("Hola")
}
}, [me])
return (
<NavigationContainer>
{auth.current ? <GeneralStack /> : <AuthStack />}
</NavigationContainer>
)
}
export default Router
Provider user,js:
import React, { useEffect, createContext, useState } from "react"
import AsyncStorage from "#react-native-async-storage/async-storage"
export const UserContext = createContext()
const UserProvider = ({ children }) => {
const [me, setMe] = useState(undefined)
const validStorage = async () => {
try {
const miSesion = await AsyncStorage.getItem("sesion")
console.log(miSesion)
setMe(JSON.parse(miSesion))
} catch (error) {
console.log(`ERROR: ${error.message}`)
}
}
useEffect(() => {
validStorage()
}, [])
return (
<UserContext.Provider value={{ me, setMe }}>
{children}
</UserContext.Provider>
)
}
export default UserProvider
GeneralStack:
import { createNativeStackNavigator } from "#react-navigation/native-stack"
import React from "react"
import TabStack from "./TabStack"
//import TabStack from "./TabStack"
const GeneralScreen = createNativeStackNavigator()
const GeneralStack = () => {
return (
<GeneralScreen.Navigator screenOptions={{ headerShown: false }}>
<GeneralScreen.Screen name="Tabs" component={TabStack} />
</GeneralScreen.Navigator>
)
}
export default GeneralStack
AuthStack:
import { createNativeStackNavigator } from "#react-navigation/native-stack"
import React from "react"
import Login from "../Screens/Login"
import Registro from "../Screens/Registro/Registro"
import SplashScreen from "../SplashScreen"
const AuthScreen = createNativeStackNavigator()
const AuthStack = () => {
return (
<AuthScreen.Navigator
initialRouteName="Splash"
screenOptions={{ headerShown: false }}>
<AuthScreen.Screen name="Login" component={Login} />
<AuthScreen.Screen name="Register" component={Registro} />
<AuthScreen.Screen name="Splash" component={SplashScreen} />
</AuthScreen.Navigator>
)
}
export default AuthStack
Login:
import React, { useState, useContext } from "react"
import {
Image,
ScrollView,
StatusBar,
Text,
TouchableOpacity,
View,
} from "react-native"
import { useNavigate } from "../../Hooks/useNavigate"
import MyTextInput from "../../components/MyTextInput"
import colors from "../../styles/colors"
import { loginStyles } from "../../styles/styles"
import { UserContext } from "../../context/Usuario"
import AsyncStorage from "#react-native-async-storage/async-storage"
export default function Login() {
const [, setIsSession] = useState(false)
const { setMe } = useContext(UserContext)
const navigate = useNavigate()
const [hidePassword, sethidePassword] = React.useState(false)
const [user] = useState({ user: "admin", password: "admin123" })
const [form, setForm] = useState({ user: "", password: "" })
const getStorage = async () => {
if (await AsyncStorage.getItem("sesion")) {
setIsSession(true)
} else {
setIsSession(false)
}
}
const signIn = async () => {
try {
console.log(user)
if (form.user === user.user && form.password === user.password) {
await AsyncStorage.setItem("sesion", JSON.stringify(form))
setMe(form)
setIsSession(true)
}
} catch (error) {
console.error(error)
}
}
const closeSesion = async () => {
await AsyncStorage.removeItem("sesion")
getStorage()
}
return (
<ScrollView contentContainerStyle={[loginStyles.container]}>
<StatusBar backgroundColor={colors.PURPLE} translucent={true} />
<View style={loginStyles.logo}>
<Image
source={require("../../recursos/images/Logo.png")}
style={{ height: 250, width: 250 }}
/>
</View>
<MyTextInput
onChangeText={(text: string) => {
setForm(state => ({ ...state, user: text }))
}}
keyboardType="email-address"
placeholder="E-mail"
/>
<MyTextInput
onChangeText={(text: string) => {
setForm(state => ({ ...state, password: text }))
}}
keyboardType={null}
placeholder="Contraseña"
bolGone={true}
secureTextEntry={hidePassword}
onPress={() => sethidePassword(!hidePassword)}
/>
<View style={loginStyles.btnMain}>
<TouchableOpacity onPress={signIn}>
<Text style={loginStyles.btntxt}>Iniciar Sesión</Text>
</TouchableOpacity>
</View>
<View style={loginStyles.btnTransparent}>
<TouchableOpacity
onPress={() => navigate({ screen: "Register" })}>
<Text
style={[loginStyles.btntxt, { color: colors.PURPLE }]}>
Registrarse
</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity>
<Text
style={[
loginStyles.txtTransparent,
{ textDecorationLine: "none" },
]}>
Olvide mi contraseña
</Text>
</TouchableOpacity>
</View>
</ScrollView>
)
}
Home:
import AsyncStorage from "#react-native-async-storage/async-storage"
import React, { useState } from "react"
import { Image, ScrollView, TouchableOpacity } from "react-native"
import { Calendar } from "react-native-calendars"
import { Text } from "react-native-elements"
import { useNavigate } from "../../Hooks/useNavigate"
import colors from "../../styles/colors"
const Home = () => {
const [showModal, setShowModal] = useState(false)
const [date, setDate] = useState<string>()
const navigate = useNavigate()
const [isSession, setIsSession] = useState(false)
const getStorage = async () => {
const data = await AsyncStorage.getItem("sesion")
console.log(data)
if (data) {
setIsSession(true)
} else {
setIsSession(false)
}
}
const closeSesion = async () => {
await AsyncStorage.removeItem("sesion")
getStorage()
}
return (
<ScrollView>
<TouchableOpacity onPress={() => closeSesion()}>
<Text>Hola porque soy bien molon</Text>
</TouchableOpacity>
<Image
source={require("../../recursos/images/coralio_logo.png")}
style={{
marginTop: 40,
height: 110,
width: "80%",
justifyContent: "center",
alignSelf: "center",
}}
/>
<Calendar
theme={{
selectedDayBackgroundColor: colors.BLACK,
arrowColor: colors.WHITE,
monthTextColor: colors.WHITE,
}}
style={{
backgroundColor: colors.PURPLE,
borderRadius: 10,
elevation: 4,
marginTop: 60,
margin: 10,
height: 400,
}}
onDayPress={day => {
console.log(day.dateString)
setDate(day.dateString)
setShowModal(false)
}}
onMonthChange={() => {}}
initialDate={"2023-01-16"}
minDate={new Date()
.toLocaleDateString("es-US", {
year: "numeric",
month: "2-digit",
day: "numeric",
formatMatcher: "basic",
})
.split("/")
.reverse()
.join("-")}
markedDates={{
day: {
marked: true,
dotColor: colors.WHITE,
selected: true,
selectedColor: colors.PURPLE,
},
}}
//maxDate={"2023-12-31"}
//hideExtraDays={false}
//disableArrowLeft={true}
//disableArrowRight={true}
//hideArrows={true}
//hideDayNames={true}
/>
</ScrollView>
)
}
export default Home
The problem I have is when doing the close session in home, if in login it sends me from the authstack view to generalstack, when I do the close session it doesn't send me back to login, but it does clean the state of the variable from asyncstorage.
Help :(
It looks like you're not clearing the me variable in your context when the user ends the session. I think your closeSesion method should look like this:
const closeSesion = async () => {
setMe(null)
await AsyncStorage.removeItem("sesion")
getStorage()
}
I'm a beginner in react native, I'm struggling into Login/Register functions, in my metro, it doesn't show login successfully just like in my backend, please help me!
This is my backend result.
And this is my code Login.js
In my metro, it shows no results, as It should show success:true or something like that as many tutorials I checked on youtube, thanks in advance.
import React, { useState } from 'react'
import { TouchableOpacity, StyleSheet, View } from 'react-native'
import { Text } from 'react-native-paper'
import Background from '../components/Background'
import Logo from '../components/Logo'
import Header from '../components/Header'
import Button from '../components/Button'
import TextInput from '../components/TextInput'
import BackButton from '../components/BackButton'
import { theme } from '../core/theme'
import { emailValidator } from '../helpers/emailValidator'
import { passwordValidator } from '../helpers/passwordValidator'
export default function login({ navigation }) {
const [email_user, setEmail_user] = useState({ value: '', error: '' })
const onLoginPressed = () => {
const emailError = emailValidator(email_user.value)
const passwordError = passwordValidator(password.value)
if (emailError || passwordError) {
setEmail_user({ ...email_user, error: emailError })
setPassword({ ...password, error: passwordError })
return
}
navigation.reset({
index: 0,
routes: [{ name: 'Home' }],
})
}
const [password, setPassword] = useState("");
const login = () => {
const data = { email_user: email_user, password: password };
axios.post('http://10.0.2.2:8000/api/auth/login', data).then((response) => {
if (response.data.error) {
alert(response.data.error);
} else {
sessionStorage.setItem("accessToken", response.data);
history.push("/");
}
});
};
return (
<Background>
<BackButton goBack={navigation.goBack} />
<Logo />
<Header></Header>
<TextInput
label="Email"
returnKeyType="next"
value={email_user.value}
onChangeText={(text) => setEmail_user({ value: text, error: '' })}
error={!!email_user.error}
errorText={email_user.error}
autoCapitalize="none"
autoCompleteType="email"
textContentType="emailAddress"
keyboardType="email-address"
/>
<TextInput
label="Password"
returnKeyType="done"
value={password.value}
onChangeText={(text) => setPassword({ value: text, error: '' })}
error={!!password.error}
errorText={password.error}
secureTextEntry
/>
<View style={styles.forgotPassword}>
<TouchableOpacity
onPress={() => navigation.navigate('reset')}
>
<Text style={styles.forgot}>Forgot your password?</Text>
</TouchableOpacity>
</View>
<Button mode="contained" onPress={onLoginPressed}>
Login
</Button>
<View style={styles.row}>
<Text>Don’t have an account? </Text>
<TouchableOpacity onPress={() => navigation.replace('register')}>
<Text style={styles.link}>Sign up</Text>
</TouchableOpacity>
</View>
</Background>
)
}
const styles = StyleSheet.create({
forgotPassword: {
width: '100%',
alignItems: 'flex-end',
marginBottom: 24,
},
row: {
flexDirection: 'row',
marginTop: 4,
},
forgot: {
fontSize: 13,
color: theme.colors.secondary,
},
link: {
fontWeight: 'bold',
color: theme.colors.blue,
},
})
firebase.js:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
import {getAuth} from "firebase/auth";
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: ****,
authDomain: ****,
projectId: ****,
storageBucket: ****,
messagingSenderId: ****,
appId: ****
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const auth = getAuth()
loginScreen.js
import { auth } from '../firebase'
import { createUserWithEmailAndPassword } from "firebase/auth"
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSignUp = async () => {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
}
New error appears when I key in the following: Email: Test#test.com, password:test
I have also refresh the firebase authentication page, no new user is added it. Also, I am referring to the guide: https://www.youtube.com/watch?v=ql4J6SpLXZA and in the video, the creator used 'matt#test.com' for email and it worked but when I try to do the same it has the warning problem and it is not synced in the firebase authentication table
How can I solve this problem?
Also, in this case, how can I code my loginscreen.js to catch when register fail?
I really need some help/advice on this. Thank you!
LoginScreen.js (Entire thing)
import { KeyBoardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import React, { useEffect, useState } from 'react'
import KeyboardAvoidingView from 'react-native/Libraries/Components/Keyboard/KeyboardAvoidingView'
import { auth } from '../firebase'
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth"
import { useNavigation } from '#react-navigation/core'
const LoginScreen = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const navigation = useNavigation()
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
if(user){
navigation.replace("Home")
}
})
return unsubscribe
})
const handleSignUp = async () => {
try {
if (email && password) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log('Registered as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
const handleLogin = async () => {
try {
if (email && password) {
const { user } = await signInWithEmailAndPassword(auth, email, password)
console.log('Logged in as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
return (
<KeyboardAvoidingView //To prevent keyboard from blocking the writing area
style={styles.container}
behavior = "padding"
>
<View style = {styles.inputContainer}>
<TextInput
placeholder = "Email"
value={email}
onChangeText ={text => setEmail(text)}
style = {styles.input}
/>
<TextInput
placeholder = "Password"
value={password}
onChangeText ={text => setPassword(text)}
style = {styles.input}
secureTextEntry //Hide password
/>
</View>
<View style = {styles.buttonContainer}>
<TouchableOpacity
onPress = {handleLogin}
style = {styles.button}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = {handleSignUp}
style = {[styles.button, styles.buttonOutline]}
>
<Text style={styles.buttonOutlineText}>Register</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
export default LoginScreen
const styles = StyleSheet.create({ //To make the text area for username and password to be center. If not it will be at the top left hand corner
container:{
flex:1,
justifyContent: 'center',
alignItems:'center',
},
inputContainer:{
width: '80%'
},
input:{ //Not working?
backgroundColor: 'white',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10, //make edge more circle
marginTop: 5, //Spacing between the input boxes
},
buttonContainer:{
width: '60%',
justifyContent: 'center',
alignItems : 'center',
marginTop: 40,
},
button:{
backgroundColor: '#0782F9',
width: '100%',
padding: 15, //Making the button enlarge in horizontal and vertical
borderRadius: 10,
alignItems: 'center',
},
buttonOutline:{
backgroundColor: 'white',
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2, //Without the width, the colour won't show
},
buttonText:{ //For the login button
color: 'white',
fontWeight:'700',
fontSize: 16,
},
buttonOutlineText:{ //For the register button
color: '#0782F9',
fontWeight:'700',
fontSize: 16,
},
})
To avoid crashes I prefer you add try catch to your code like this:
import { auth } from '../firebase'
import { createUserWithEmailAndPassword } from "firebase/auth"
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSignUp = async () => {
try {
if (email && password) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
}
} catch (e) {
console.log({e});
}
}
For error messages:
import { KeyBoardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import React, { useEffect, useState } from 'react'
import KeyboardAvoidingView from 'react-native/Libraries/Components/Keyboard/KeyboardAvoidingView'
import { auth } from '../firebase'
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth"
import { useNavigation } from '#react-navigation/core'
const LoginScreen = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [showError, setShowError] = useState(false);
const navigation = useNavigation()
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
if(user){
navigation.replace("Home")
}
})
return unsubscribe
})
const handleSignUp = async () => {
try {
if (email && password) {
setShowError(false);
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log('Registered as :' , user.email);
}
} catch (error) {
console.log({error});
setShowError(true);
}
}
const handleLogin = async () => {
try {
if (email && password) {
const { user } = await signInWithEmailAndPassword(auth, email, password)
console.log('Logged in as :' , user.email);
}
} catch (error) {
console.log({error});
}
}
return (
<KeyboardAvoidingView //To prevent keyboard from blocking the writing area
style={styles.container}
behavior = "padding"
>
<View style = {styles.inputContainer}>
<TextInput
placeholder = "Email"
value={email}
onChangeText ={text => setEmail(text)}
style = {styles.input}
/>
<TextInput
placeholder = "Password"
value={password}
onChangeText ={text => setPassword(text)}
style = {styles.input}
secureTextEntry //Hide password
/>
</View>
{showError && <View style={styles.error}>
<Text>Wrong username or password</Text>
</View>}
<View style = {styles.buttonContainer}>
<TouchableOpacity
onPress = {handleLogin}
style = {styles.button}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = {handleSignUp}
style = {[styles.button, styles.buttonOutline]}
>
<Text style={styles.buttonOutlineText}>Register</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
export default LoginScreen
const styles = StyleSheet.create({ //To make the text area for username and password to be center. If not it will be at the top left hand corner
container:{
flex:1,
justifyContent: 'center',
alignItems:'center',
},
inputContainer:{
width: '80%'
},
input:{ //Not working?
backgroundColor: 'white',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 10, //make edge more circle
marginTop: 5, //Spacing between the input boxes
},
buttonContainer:{
width: '60%',
justifyContent: 'center',
alignItems : 'center',
marginTop: 40,
},
button:{
backgroundColor: '#0782F9',
width: '100%',
padding: 15, //Making the button enlarge in horizontal and vertical
borderRadius: 10,
alignItems: 'center',
},
buttonOutline:{
backgroundColor: 'white',
marginTop: 5,
borderColor: '#0782F9',
borderWidth: 2, //Without the width, the colour won't show
},
buttonText:{ //For the login button
color: 'white',
fontWeight:'700',
fontSize: 16,
},
buttonOutlineText:{ //For the register button
color: '#0782F9',
fontWeight:'700',
fontSize: 16,
},
error: {
backgroundColor: 'red',
padding: 16,
textAlign: 'center'
},
})
I'd recommend handling some common errors such as short password or invalid email format locally using Javascript than to make an API call everytime without validation.
const handleSignUp = async () => {
if (email && password.length >= 8) {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
console.log(user);
} else {
console.log("Please enter a valid email and password")
}
}
how can I prevent the app from minimizing / exiting when pushing back button on my device?
Im trying to assign "browsers back" functionality when pressing back button on my device, heres my code:
import 'react-native-get-random-values';
import React, { useState, useRef, Component, useEffect } from 'react'
import {
Alert,
SafeAreaView,
StyleSheet,
StatusBar,
View,
Text,
ScrollView,
BackHandler,
RefreshControl
} from 'react-native'
import WebView from 'react-native-webview'
import Icon from 'react-native-vector-icons/FontAwesome';
import { Button } from 'react-native-elements';
const App = () => {
function backButtonHandler(){}
function refreshHandler(){
if (webviewRef.current) webviewRef.current.reload()
}
useEffect(() => {
BackHandler.addEventListener("hardwareBackPress", backButtonHandler);
return () => {
BackHandler.removeEventListener("hardwareBackPress", backButtonHandler);
};
}, [backButtonHandler]);
let jscode = `window.onscroll=function(){window.ReactNativeWebView.postMessage(document.documentElement.scrollTop||document.body.scrollTop)}`;
const [canGoBack, setCanGoBack] = useState(false)
const [currentUrl, setCurrentUrl] = useState('')
const [refreshing, setRefreshing] = useState(false);
const [scrollviewState, setEnableRefresh] = useState(false);
const webviewRef = useRef(null)
const scrollviewRef = useRef(false)
backButtonHandler = () => {
if (webviewRef.current) webviewRef.current.goBack()
}
return (
<>
<StatusBar barStyle='dark-content' />
<SafeAreaView style={styles.flexContainer}>
<ScrollView
contentContainerStyle={styles.flexContainer}
refreshControl={
<RefreshControl refreshing={false} onRefresh={refreshHandler} ref={scrollviewRef} enabled={ (scrollviewState) ? true : false } />
}>
<WebView
source={{ uri: 'https://youtube.com' }}
startInLoadingState={true}
ref={webviewRef}
onNavigationStateChange={navState => {
setCanGoBack(navState.canGoBack)
setCurrentUrl(navState.url)
}}
injectedJavaScript={jscode}
onMessage={(event)=>{
let message = event.nativeEvent.data;
let num = parseInt(message);
if(num==0){setEnableRefresh(true)}
else{setEnableRefresh(false)}
}}
/>
</ScrollView>
<View style={styles.tabBarContainer}>
<Button onPress={backButtonHandler}
icon={
<Icon
name="arrow-left"
size={15}
color="white"
/>
}
containerStyle={styles.buttonx}
title="Back"
/>
</View>
</SafeAreaView>
</>
)
}
const styles = StyleSheet.create({
flexContainer: {
flex: 1
},
tabBarContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
backgroundColor: 'orange'
},
buttonx: {
backgroundColor:'blue',
width:'100%'
}
})
export default App
my problem is when I press the back button on my device, it does call backButtonHandler function and my webview navigates back, but at the same time the app minimizes too.. is there a way to prevent this?
change your backButtonHandler Method to just return true, when your backHandler Method does return true, it actually does nothing onPress Back button :
backButtonHandler = () => {
return true;
}
I really can't see how I'm getting undefined is not object (evaluating 'ReactPropTypes.string) error in my iOS simulator. My code in the WebStorm IDE isn't throw me any errors. I've tried deleting my node_modules folder and then running npm install in Terminal because that usually solves most problems, but not in this case.
Here's Secured.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ScrollView, Text, View, Button } from 'react-native';
import { logout } from '../redux/actions/auth';
import DropdownMenu from 'react-native-dropdown-menu';
import Icon from './Icon';
class Secured extends Component {
render() {
var data = [["Choice 1"], ["Choice 2"], ["Choice 3"], ["Choice 4"]];
return(
<ScrollView style={{padding: 20}}>
<Icon/>
<Text style={{fontSize: 27}}>
{`Welcome ${this.props.username}`}
</Text>
<View style={{flex: 1}}>
<DropdownMenu style={{flex: 1}}
bgColor={"purple"} //the background color of the head, default is grey
tintColor={"white"} //the text color of the head, default is white
selectItemColor={"orange"} //the text color of the selected item, default is red
data={data}
maxHeight={410} // the max height of the menu
handler={(selection, row) => alert(data[selection][row])} >
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}} >
</View>
</DropdownMenu>
</View>
<View style={{margin: 20}}/>
<Button onPress={(e) => this.userLogout(e)} title="Logout"/>
</ScrollView>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
username: state.auth.username
};
}
const mapDispatchToProps = (dispatch) => {
return {
onLogout: () => { dispatch(logout()); }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Secured);
Here's Login.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ScrollView, Text, TextInput, View, Button, StyleSheet } from 'react-native';
import { login } from '../redux/actions/auth';
import {AuthenticationDetails, CognitoUser, CognitoUserAttribute, CognitoUserPool} from '../lib/aws-cognito-identity';
const awsCognitoSettings = {
UserPoolId: 'something',
ClientId: 'something'
};
class Login extends Component {
constructor (props) {
super(props);
this.state = {
page: 'Login',
username: '',
password: ''
};
}
get alt () { return (this.state.page === 'Login') ? 'SignUp' : 'Login'; }
handleClick (e) {
e.preventDefault();
const userPool = new CognitoUserPool(awsCognitoSettings);
// Sign up
if (this.state.page === 'SignUp') {
const attributeList = [
new CognitoUserAttribute({ Name: 'email', Value: this.state.username })
];
userPool.signUp(
this.state.username,
this.state.password,
attributeList,
null,
(err, result) => {
if (err) {
alert(err);
this.setState({ username: '', password: '' });
return;
}
console.log(`result = ${JSON.stringify(result)}`);
this.props.onLogin(this.state.username, this.state.password);
}
);
} else {
const authDetails = new AuthenticationDetails({
Username: this.state.username,
Password: this.state.password
});
const cognitoUser = new CognitoUser({
Username: this.state.username,
Pool: userPool
});
cognitoUser.authenticateUser(authDetails, {
onSuccess: (result) => {
console.log(`access token = ${result.getAccessToken().getJwtToken()}`);
this.props.onLogin(this.state.username, this.state.password);
},
onFailure: (err) => {
alert(err);
this.setState({ username: '', password: '' });
return;
}
});
}
}
togglePage (e) {
this.setState({ page: this.alt });
e.preventDefault();
}
render() {
return (
<ScrollView style={{padding: 20}}>
{/*<Text style={styles.title}>Welcome!</Text>*/}
<TextInput
style={styles.pw}
placeholder=' Email Address'
autoCapitalize='none'
autoCorrect={false}
autoFocus={true}
keyboardType='email-address'
value={this.state.username}
onChangeText={(text) => this.setState({ username: text })} />
<TextInput
style={styles.pw}
placeholder=' Password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
value={this.state.password}
onChangeText={(text) => this.setState({ password: text })} />
<View style={{margin: 7}}/>
<Button onPress={(e) => this.handleClick(e)} title={this.state.page}/>
<View style={{margin: 7, flexDirection: 'row', justifyContent: 'center'}}>
<Text onPress={(e) => this.togglePage(e)} style={styles.buttons}>
{this.alt}
</Text>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
title: {
fontSize: 27,
textAlign: 'center'
},
icon: {
position: 'absolute'
},
pw: {
paddingRight: 90,
justifyContent: 'flex-end',
marginBottom: 20,
backgroundColor: '#9b42f4',
height: 40,
borderWidth: 1,
borderRadius: 5
},
buttons: {
fontFamily: 'AvenirNext-Heavy'
}
});
const mapStateToProps = (state, ownProps) => {
return {
isLoggedIn: state.auth.isLoggedIn
};
}
const mapDispatchToProps = (dispatch) => {
return {
onLogin: (username, password) => { dispatch(login(username, password)); }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
Check this out, this looks like the issue you're having https://github.com/facebook/react-native/issues/14588#issuecomment-309683553
npm install react#16.0.0-alpha.12 solves the problem.