Ejemplo de inicio de sesión en React Native usando la API REQRES reqres.in/
React Native es un framework para el desarrollo de aplicaciones híbridas cross-platform
Consulta como preparar el entorno para trabajar aplicaciones en React Native en su sitio oficial reactnative.dev/docs/environment-setup
Esta aplicacion utiliza la API ReqRes para simular el uso de información válida de usuarios para así permitir o restringir el acceso.
Para controlar el flujo de autenticación se requiere de AuthContext con el uso de UseContext para ser manejado como variable global y de esta forma se tenga disponible en todas las pantallas de la aplicación
context/AuthContext.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios from 'axios';
import React, { createContext, useEffect, useState } from 'react';
const BASE_URL = 'https://reqres.in/api';
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [userInfo, setUserInfo] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [splashLoading, setSplashLoading] = useState(false);
const login = (email, password) => {
setIsLoading(true);
axios
.post(`${BASE_URL}/login`, {
email,
password,
})
.then(res => {
let userInfo = res.data;
console.log(userInfo);
setUserInfo(userInfo);
//this store login data
AsyncStorage.setItem('userInfo', JSON.stringify(userInfo));
setIsLoading(false);
})
.catch(e => {
console.log(`login error ${e}`);
setIsLoading(false);
});
};
const register = (email, password) => {
axios
.post(`${BASE_URL}/register`, {
email,
password,
})
.then(res => {
let userInfo = res.data;
console.log(userInfo);
setUserInfo(userInfo);
setIsLoading(false);
})
.catch(e => {
console.log(`register error ${e}`);
setIsLoading(false);
});
};
const logout = () => {
setIsLoading(true);
axios
.post(
`${BASE_URL}/logout`,
{},
{
headers: { Authorization: `Bearer ${userInfo.access_token}` },
},
)
.then(res => {
console.log(res.data);
AsyncStorage.removeItem('userInfo');
setUserInfo({});
setIsLoading(false);
})
.catch(e => {
console.log(`logout error ${e}`);
setIsLoading(false);
console.log(isLoading);
});
};
const isLoggedIn = async () => {
try {
setSplashLoading(true);
let userInfo = await AsyncStorage.getItem('userInfo');
userInfo = JSON.parse(userInfo);
if (userInfo) {
setUserInfo(userInfo);
}
setSplashLoading(false);
} catch (e) {
setSplashLoading(false);
console.log(`is logged in error ${e}`);
}
};
useEffect(() => {
isLoggedIn();
return () => {
setUserInfo({});
};
}, []);
return (
<AuthContext.Provider
value={{
isLoading,
userInfo,
splashLoading,
login,
logout,
register,
}}>
{children}
</AuthContext.Provider>
);
};
components/Navigation.js
import React, { useContext } from 'react';
import { Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from '../screens/HomeScreen';
import LoginScreen from '../screens/LoginScreen';
import { AuthContext } from '../context/AuthContext';
import SplashScreen from '../screens/SplashScreen';
import RegisterScreen from '../screens/RegisterScreen';
import SearchScreen from '../screens/SearchScreen';
const Stack = createNativeStackNavigator();
const Navigation = () => {
const { userInfo, splashLoading, logout } = useContext(AuthContext);
return (
<NavigationContainer>
<Stack.Navigator>
{splashLoading ? (
<Stack.Screen
name="Splash Screen"
component={SplashScreen}
options={{ headerShown: false }}
/>
) : userInfo.token ? (
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerRight: () => (
<Button title="Logout" color="#13b7dc" onPress={logout} />
),
headerStyle: {
backgroundColor: '#032541',
},
title: 'Login Demo - React Native',
headerTintColor: '#fff',
}}
/>
) : (
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
)}
<Stack.Screen
name="Register"
component={RegisterScreen}
options={{
headerStyle: {
backgroundColor: '#032541',
},
headerTintColor: '#fff',
title: 'Register',
}}
/>
<Stack.Screen
name="Search"
component={SearchScreen}
options={{
headerStyle: {
backgroundColor: '#032541',
},
headerTintColor: '#fff',
title: 'Results',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default Navigation;
screens/LoginScreen.js
import React, { useContext, useState } from 'react';
import {
View,
StyleSheet,
ActivityIndicator,
Image,
TouchableOpacity,
Text,
} from 'react-native';
import { useFormik } from 'formik';
import * as yup from 'yup';
import { TextInput } from 'react-native-paper';
import { AuthContext } from '../context/AuthContext';
const LoginScreen = ({ navigation }) => {
const [email, setEmail] = useState(null);
const [password, setPassword] = useState(null);
const { isLoading, login } = useContext(AuthContext);
const formik = useFormik({
initialValues: initialValues(),
validationSchema: yup.object(validationSchema()),
validateOnChange: false,
onSubmit: form => {
login(form.email, form.password);
},
});
return (
<View style={styles.container}>
<Image
style={styles.logo}
source={require('../images/logo.png')}
/>
<ActivityIndicator size="large" color="blue" animating={isLoading} />
<View style={styles.wrapper}>
<Text style={styles.textError}>{formik.errors.email}</Text>
<TextInput
mode="outlined"
label="Enter Email"
value={formik.values.email}
style={styles.input}
onChangeText={text => formik.setFieldValue('email', text)}
/>
<Text style={styles.textError}>{formik.errors.password}</Text>
<TextInput
style={styles.input}
mode="outlined"
value={formik.values.password}
label="Enter password"
onChangeText={text => formik.setFieldValue('password', text)}
secureTextEntry
/>
<TouchableOpacity
onPress={formik.handleSubmit}
style={styles.loginButton}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
<Text style={{ textAlign: 'center', fontSize: 16 }}>
"email": "eve.holt@reqres.in" {'\n'}
"password": "cityslicka"
</Text>
<Text>{'\n'}</Text>
<Text style={{ color: 'blue', fontSize: 20, textAlign: 'center' }}
onPress={() => navigation.navigate('Register')}>
Register
</Text>
</View>
</View>
);
};
function initialValues() {
return {
email: '',
password: '',
};
}
function validationSchema() {
return {
email: yup
.string()
.email('Email format is invalid')
.required('Email is required'),
password: yup.string().required('Password is required'),
};
}
const styles = StyleSheet.create({
container: {
paddingVertical: 40,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f2f2f2',
},
wrapper: {
width: '80%',
},
input: {
marginBottom: 20,
},
loginButton: {
elevation: 6,
backgroundColor: '#13b7dc',
borderRadius: 30,
paddingVertical: 6,
paddingHorizontal: 6,
paddingVertical: 15,
marginTop: 10,
},
buttonText: {
fontSize: 16,
color: '#fff',
fontWeight: 'bold',
alignSelf: 'center',
textTransform: 'uppercase',
},
textError: {
color: '#ab0000',
fontSize: 12,
},
logo: {
width: 180,
height: 32,
resizeMode: 'stretch',
},
});
export default LoginScreen;