I am currently developing a mobile application with the backend using Appwrite. The issue I am facing is that, after successfully logging in and pressing the pressable “Log In”, I need to reload the app to be redirected into the main pages of the app, is it because when the screen is rendered the user state has not been updated yet? If so how can I fix it. Any help is greatly appreciated.
This is my GuestOnly component which I am wrapping all the files of the main pages in.
import { useRouter } from "expo-router"
import { useUser } from "../../hooks/useUser"
import { useEffect } from "react"
import ThemedLoader from "../ThemedLoader"
const GuestOnly = ({ children }) => {
const { user, authChecked } = useUser()
const router = useRouter()
useEffect(() => {
if (authChecked && user !== null) {
router.replace('/profilepage');
}
}, [user, authChecked])
if (!authChecked || user) {
return (
<ThemedLoader/>
)
}
return children
}
export default GuestOnly
This is my UserContext file where I created the log in function
import { createContext, useState, useEffect } from "react";
import { account } from "../lib/appwrite"
import { ID } from "react-native-appwrite"
export const UserContext = createContext();
export function UserProvider({ children }) {
const [user, setUser] = useState(null)
const [authChecked, setAuthChecked] = useState(false)
async function login(email, password) {
try {
await account.createEmailPasswordSession(email, password)
//const response = await account.get()
//setUser(response)
await getInitialUserValue()
} catch (error) {
throw Error(error.message)
}
}
async function register(email, password) {
try {
// Check if user is already logged in
const current = await account.get();
if (current) {
throw new Error("You are already logged in. Please log out before registering a new account.");
}
} catch (error) {
// If not logged in, Appwrite throws error with code 401 (unauthorized)
if (error.code !== 401) {
throw new Error(error.message);
}
}
try {
await account.create(ID.unique(), email, password);
await login(email, password);
} catch (error) {
if (error.code === 409) { // 409 is usually "Conflict" for duplicate
throw new Error("This email is already registered. Please log in or use another email.");
}
throw new Error(error.message);
}
}
async function logout() {
await account.deleteSession("current")
setUser(null)
}
async function getInitialUserValue() {
try {
const res = await account.get()
setUser(res)
} catch (error) {
setUser(null)
} finally {
setAuthChecked(true)
}
}
useEffect(() => {
getInitialUserValue()
}, [])
return (
<UserContext.Provider value ={{ user, login, register, logout, authChecked }}>
{children}
</UserContext.Provider>
)
}
This is my login page file
import { View, Text, TextInput, Pressable, StyleSheet, Keyboard, TouchableWithoutFeedback } from 'react-native';
import { useRouter } from 'expo-router';
import { useState, useEffect } from 'react';
import { useUser } from '../../hooks/useUser';
export default function LoginPage() {
const router = useRouter();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const { user, login } = useUser();
const handleSubmit = async () => {
setError(null);
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
if (!emailRegex.test(email)) {
setError('Please enter a valid email address.');
return;
}
try {
await login(email, password);
} catch (error) {
setError(error.message);
}
};
return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.overlay}>
<Text style={styles.title}>Welcome Back</Text>
<TextInput
placeholder="Email"
placeholderTextColor="#999"
style={styles.input}
onChangeText={setEmail}
value={email}
/>
<TextInput
placeholder="Password"
placeholderTextColor="#999"
onChangeText={setPassword}
value={password}
secureTextEntry
style={styles.input}
/>
<Pressable style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonText}>Log In</Text>
</Pressable>
<View style={{ width: '100%', height: 60 }}>
{error && <Text style={styles.error}>{error}</Text>}
</View>
<Pressable style={styles.registerButton} onPress={() => router.push('/')}>
<Text style={styles.registerText}>← Back To Start</Text>
</Pressable>
<Pressable style={styles.registerButton} onPress={() => router.push('/signuppage')}>
<Text style={styles.registerText}>Register Instead</Text>
</Pressable>
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: '#FAF3DD',
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 24,
},
title: {
fontSize: 32,
fontWeight: '700',
color: '#333',
marginBottom: 28,
},
input: {
width: '100%',
borderWidth: 1,
borderColor: '#ccc',
backgroundColor: '#fff',
color: '#333',
padding: 14,
borderRadius: 10,
marginBottom: 16,
fontSize: 16,
},
button: {
backgroundColor: '#FF8C42',
padding: 14,
borderRadius: 10,
alignItems: 'center',
width: '100%',
shadowColor: '#000',
shadowOpacity: 0.15,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 3,
marginBottom: 16,
},
buttonText: {
color: '#fff',
fontWeight: '600',
fontSize: 16,
},
error: {
color: '#fff',
backgroundColor: '#D9534F',
padding: 10,
borderRadius: 6,
textAlign: 'center',
},
registerButton: {
marginTop: 8,
paddingVertical: 10,
paddingHorizontal: 20,
borderColor: '#FF8C42',
borderWidth: 1,
borderRadius: 8,
backgroundColor: '#fff8f1',
},
registerText: {
color: '#FF8C42',
fontSize: 14,
fontWeight: '600',
textAlign: 'center',
},
});