I am trying to make a Todo/Notes App with Firebase as DB. The app is working perfectly in sync with the FirestoreDB, but every time I close and reopen the app, the app seems to delete the previous credentials and create a new user altogether and all the previous notes are gone from the app, which still exist on the FirestoreDB. Can anyone tell me what am I doing wrong?
This is the App.js
import {
StyleSheet,
Text,
View,
TouchableOpacity,
FlatList,
Modal,
ActivityIndicator,
} from 'react-native';
import colors from './Colors';
import { AntDesign } from '#expo/vector-icons';
import TodoList from './components/TodoList';
import AddListModal from './components/AddListModal';
import Fire from './Fire';
export default class App extends React.Component {
state = {
addTodoVisibile: false,
lists: [],
user: {},
loading: true,
};
componentDidMount() {
firebase = new Fire((error, user) => {
if (error) {
return alert('Something went wrong');
}
firebase.getLists(lists => {
this.setState({ lists, user }, () => {
this.setState({ loading: false });
});
});
this.setState({ user });
});
}
componentWillUnmount() {
firebase.detach();
}
toggleAddTodoModal() {
this.setState({ addTodoVisibile: !this.state.addTodoVisibile });
}
renderList = list => {
return <TodoList list={list} updateList={this.updateList} />;
};
addList = list => {
firebase.addList({
name: list.name,
color: list.color,
todos: [],
});
};
updateList = list => {
firebase.updateList(list);
};
deleteList = list => {
firebase.deleteList(list);
};
renderList = list => {
return (
<TodoList
list={list}
updateList={this.updateList}
deleteList={this.deleteList}
/>
);
};
render() {
if (this.state.loading) {
return (
<View style={styles.container}>
<ActivityIndicator size={50} color={colors.highlight} />
</View>
);
}
return (
<View style={styles.container}>
<Modal
animationType='slide'
visible={this.state.addTodoVisibile}
onRequestClose={() => this.toggleAddTodoModal()}
>
<AddListModal
closeModal={() => this.toggleAddTodoModal()}
addList={this.addList}
/>
</Modal>
<View style={{ flexDirection: 'row' }}>
<View style={styles.divider} />
<Text style={styles.title}>
Post
<Text
style={{
fontWeight: '500',
color: colors.highlight,
}}
>
It
</Text>
</Text>
<View style={styles.divider} />
</View>
<View style={{ marginVertical: 48 }}>
<TouchableOpacity
style={styles.addList}
onPress={() => this.toggleAddTodoModal()}
>
<AntDesign name='plus' size={25} color={colors.white} />
</TouchableOpacity>
<Text style={styles.add}>Add a List</Text>
</View>
<View style={{ height: 275 }}>
<FlatList
data={this.state.lists}
keyExtractor={item => item.id.toString()}
horizontal={true}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => this.renderList(item)}
keyboardShouldPersistTaps='always'
/>
</View>
<Text style={styles.delete}>
<Text style={styles.highlight}>(</Text>
Long Press on List to Delete
<Text style={styles.highlight}>)</Text>
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
alignItems: 'center',
justifyContent: 'center',
},
divider: {
backgroundColor: colors.highlight,
height: 1,
flex: 1,
alignSelf: 'center',
},
title: {
fontSize: 38,
fontWeight: '800',
color: colors.white,
paddingHorizontal: 64,
},
addList: {
borderWidth: 2,
borderColor: colors.highlight,
borderRadius: 4,
padding: 16,
alignItems: 'center',
},
add: {
color: colors.white,
fontWeight: '600',
fontSize: 16,
marginTop: 8,
},
delete: {
color: colors.white,
fontWeight: '500',
fontSize: 12.5,
position: 'absolute',
bottom: 8,
},
highlight: {
color: colors.highlight,
},
});
and this is Fire.js
import 'firebase/compat/firestore';
import 'firebase/compat/auth';
const firebaseConfig = {
};
class Fire {
constructor(callback) {
this.init(callback);
}
init(callback) {
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
firebase.auth().onAuthStateChanged(user => {
if (user) {
callback(null, user);
} else {
firebase
.auth()
.signInAnonymously()
.catch(error => {
callback(error);
});
}
});
}
getLists(callback) {
let ref = this.ref.orderBy('name');
this.unsubscribe = ref.onSnapshot(snapshot => {
lists = [];
snapshot.forEach(doc => {
lists.push({ id: doc.id, ...doc.data() });
});
callback(lists);
});
}
addList(list) {
let ref = this.ref;
ref.add(list);
}
updateList(list) {
let ref = this.ref;
ref.doc(list.id).update(list);
}
deleteList(list) {
let ref = this.ref;
ref.doc(list.id).delete();
}
get userId() {
return firebase.auth().currentUser.uid;
}
get ref() {
return firebase
.firestore()
.collection('users')
.doc(this.userId)
.collection('lists');
}
detach() {
this.unsubscribe();
}
}
export default Fire;
On most environments the Firebase Authentication SDK will automatically persist the user credentials and restore them when the app/page is reloaded, and then call your onAuthStateChanged handler.
On React Native this is not possible by default though, so I recommend checking out the Firebase documentation on managing auth persistence..
Related
Screen shot of current list
I would like to display a list that is grabbing data from my Firebase Firestore Database. I'm using expo for this project and react native. I can see the boxes form the list, but can't see the titles or the chevrons. I've tried a few formatting solutions and couldn't resolve the issue. I'm still able to add to the list and view the list once clicked.
import React, { Component } from "react";
import {
StyleSheet,
ScrollView,
ActivityIndicator,
View,
Text,
} from "react-native";
import { colors, ListItem } from "react-native-elements";
import firebase from "../../firebase";
class SearchEntry extends Component {
constructor() {
super();
this.firestoreRef=
firebase.firestore().collection("RepairDocuments");
this.state = {
isLoading: true,
entryArr: [],
};
}
componentDidMount() {
this.unsubscribe =
this.firestoreRef.onSnapshot(this.getCollection);
}
componentWillUnmount() {
this.unsubscribe();
}
getCollection = (querySnapshot) => {
const entryArr = [];
querySnapshot.forEach((res) => {
const { unit, date, bio } = res.data();
entryArr.push({
key: res.id,
res,
unit,
date,
bio,
});
});
this.setState({
entryArr,
isLoading: false,
});
};
render() {
if (this.state.isLoading) {
return (
<View style={styles.preloader}>
<ActivityIndicator size="large" color="#9E9E9E" />
</View>
);
}
return (
<ScrollView style={styles.container}>
{this.state.entryArr.map((item, i) => {
return (
<ListItem
titleStyle={{ color: "black", fontWeight: "bold" }}
style={{ height: 55 }}
key={i}
chevron
title={item.unit}
subtitle={item.bio}
onPress={() => {
this.props.navigation.navigate("Details", {
userkey: item.key,
});
}}
/>
);
})}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 55,
flex: 1,
fontSize: 18,
textTransform: "uppercase",
fontWeight: "bold",
backgroundColor: colors.black,
},
preloader: {
left: 0,
right: 0,
top: 0,
bottom: 0,
position: "absolute",
alignItems: "center",
justifyContent: "center",
},
text: {
color: colors.black,
backgroundColor: colors.black,
},
});
export default SearchEntry;
I'm trying to make an app where I can add item in a flatlist . Then each item I can navigate to a new page only for that specific item . In that page, I can add another flatlist.
To explain it more, lets say I add few Classroom item in the flatlist (Classroom A, Classroom B, Classroom C). When I press Clasroom A , it will navigate to a page named Classroom A . In that page, I can add and delete the name of each students using another flatlist.
How can I design the page for the Classsrooms ??? Because when I add the name of the student in classroom A, the names of the students is also available in the flatlist of other Classrooms.
This is my code for the Main Menu:
import React, { useState , useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
FlatList,
Alert,
TextInput,
StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { useNavigation } from '#react-navigation/native';
export default function MainMenu(){
const [classroomInput, setClassroomInput] = useState('');
const [classroom, setClassroom] = useState([]);
const navigation = useNavigation();
useEffect(() => {
getClassroom();
}, []);
useEffect(() => {
saveClassroom(classroom);
}, [classroom]);
const saveClassroom = async (classroom) => {
try {
const stringifyClassroom = JSON.stringify(classroom);
await AsyncStorage.setItem('classroom', stringifyClassroom);
} catch (error) {
console.log(error);
}
};
const getClassroom = async () => {
try {
const classrooms = await AsyncStorage.getItem('classroom');
if (classrooms !== null) {
setClassroom(JSON.parse(classrooms));
}
} catch (error) {
console.log(error);
}
};
const addClassroom = () => {
if (classroomInput === ''){
Alert.alert('Error', 'Please input class');
} else {
const newClassroom = {
id: Math.random().toString(),
Classroom: classroomInput,
};
setClassroom([...classroom,newClassroom]);
setClassroomInput('');
}
};
const deleteClassroom = (classroomId) => {
const newClassrooms = classroom.filter(item => item.id !== classroomId);
setClassroom(newClassrooms);
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder={'Add Classrooms'}
value={classroomInput}
onChangeText={(text) => setClassroomInput(text)}
/>
<TouchableOpacity onPress={() => addClassroom()} style={styles.button}>
<Text>Add Classroom</Text>
</TouchableOpacity>
<FlatList
style={styles.flatlist}
data={classroom}
keyExtractor = { (item) => item.id.toString() }
renderItem={({ item }) => (
<TouchableOpacity onPress= {() => navigation.navigate('Classroom', item)} >
<View style={styles.listItem}>
<View>
<Text style={[styles.classText , {fontSize: 18}]}>
{item?.Classroom}
</Text>
</View>
<View >
<TouchableOpacity style={[styles.delete ]} onPress={() => deleteClassroom(classroom?.id)}>
<Icon name="remove" size={15} color={'#fff'} />
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
input: {
width: '70%',
borderBottomWidth: 1,
marginBottom: 20,
},
button: {
backgroundColor: 'lightblue',
padding: 10,
marginBottom: 10,
},
delete: {
backgroundColor: '#ff3333',
padding: 5,
color: '#fff',
borderWidth: 1,
borderColor: '#ff9999',
borderRadius: 5,
},
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '70%',
alignItems: 'center',
},
});
And this is the code for the classroom:
/* eslint-disable prettier/prettier */
import React, { useState , useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
FlatList,
Alert,
TextInput,
StyleSheet,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Classroom = ( {navigation, route}) => {
const [studentInput, setStudentInput] = useState('');
const [student, setStudent] = useState([]);
useEffect(() => {
getStudent();
}, []);
useEffect(() => {
saveStudent(student);
}, [student]);
const saveStudent = async (student) => {
try {
const stringifyStudent = JSON.stringify(student);
await AsyncStorage.setItem('student', stringifyStudent);
} catch (error) {
console.log(error);
}
};
const getStudent = async () => {
try {
const students = await AsyncStorage.getItem('student');
if (students !== null) {
setStudent(JSON.parse(students));
}
} catch (error) {
console.log(error);
}
};
const addStudent = () => {
if (studentInput === ''){
Alert.alert('Error', 'Please input student name');
} else {
const newStudent = {
id: Math.random().toString(),
Name: studentInput,
};
setStudent([...student,newStudent]);
setStudentInput('');
}
};
const deleteStudent = (studentId) => {
const newStudent = student.filter(item => item.id !== studentId);
setStudent(newStudent);
};
return (
<View styles={styles.container}>
<TouchableOpacity onPress={()=> navigation.goBack()} style={styles.button}>
<Text>Back</Text>
</TouchableOpacity>
<Text style={{fontWeight: 'bold', fontSize: 20}}>[ Classroom Name ]</Text>
<TextInput
style={styles.input}
placeholder={'Add Student Name'}
value={studentInput}
onChangeText={(text) => setStudentInput(text)}
/>
<TouchableOpacity onPress={()=> addStudent()} style={styles.button}>
<Text>Add Student</Text>
</TouchableOpacity>
<FlatList
style={styles.flatlist}
data={student}
keyExtractor = { (item) => item.id.toString() }
renderItem={({ item }) => (
<View style={styles.listItem}>
<View>
<Text style={[styles.classText , {fontSize: 18}]}>
{item?.Name}
</Text>
</View>
<View >
<TouchableOpacity style={[styles.delete ]} onPress={() => deleteStudent(item?.id)}>
<Icon name="remove" size={15} color={'#fff'} />
</TouchableOpacity>
</View>
</View>
)}
/>
</View>
);
};
export default Classroom;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
input: {
width: '70%',
borderBottomWidth: 1,
marginBottom: 20,
},
button: {
backgroundColor: 'lightblue',
padding: 10,
marginBottom: 10,
},
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '70%',
alignItems: 'center',
},
delete: {
backgroundColor: '#ff3333',
padding: 5,
color: '#fff',
borderWidth: 1,
borderColor: '#ff9999',
borderRadius: 5,
},
});
You are using the same AsyncStorage key 'student' regardless of which classroom you are looking at. You need to keep your student lists separate, so you'll need a separate key for each. Something like:
const key = `students_in_room_${classroomId}`
You can get the classroom id (A, B, C) through the route prop from your navigation.
Edit: You would use this unique key instead of the string 'students' for reading and writing to AsyncStorage. That way you can have separate stored values for each classroom.
const students = await AsyncStorage.getItem(key);
await AsyncStorage.setItem(key, stringifyStudent);
I'm new to React Native, and I'm following along with an online tutorial.
This is my App.js file:
import React, { useState, useEffect } from 'react';
import {View,Text,ImageBackground,FlatList, Image, TouchableHighlight } from 'react-native';
import bookmarkIcon from './assets/bookmark.png';
import readIcon from './assets/read.png';
import styles from './styles';
const ArticleItem = ({article}) => {
const { title, description, url, urlToImage } = article;
return (
<View style = { styles.articleContainer }>
<Image style={ styles.articleImage } source={{ uri: urlToImage }} />
<Text style= { styles.articleTitle }>
{ title }
</Text>
<Text style = { styles.articleDescription }>
{ description }
</Text>
<View style = { styles.articleBtns}>
<IconButton width= "50%" color = "white" bgcolor = "#ff5c5c" icon = { readIcon } onPress = { () => { console.log("Button pressed!")} } title = "Open" />
<IconButton width= "50%" color = "white" bgcolor = "#ff5c5c" icon = { bookmarkIcon } onPress = { () => { console.log("Button pressed!")} } title = "Read later" />
</View>
</View>
)
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
FlatListHeader = () => {
return (
<View elevation={1}
style={{
height: 100,
width: "97%",
margin: 5,
backgroundColor: "#fff",
border: 2.9,
borderColor: "black",
alignSelf: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 16,
},
shadowOpacity: 1,
shadowRadius: 7.49
}}
>
<Text style={{
textShadowColor: 'black',
textShadowOffset: { width: 1, height: 3 },
textShadowRadius: 10,
fontSize: 40,
fontWeight: '800',
flex: 1,
alignSelf: "center",
paddingTop: 30
}}
>Latest articles</Text>
</View>
);
}
const IconButton = ({title, color, bgcolor, onPress, width, icon }) =>{
return (
<TouchableHighlight onPress = { onPress } style= { { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: bgcolor } }>
<View style={ {width: width, flexDirection: 'row', justifyContent: 'center', alignItems: 'center' } }>
<Image style = { { height: 27, width:27, margin : 5 } } source = { icon }></Image>
<Text style = { {color: color }} > { title } </Text>
</View>
</TouchableHighlight>
);
}
const HomeScreen = (props) => {
console.log("articles: ", props.articles);
return (
<View>
<FlatList
data={ props.articles }
ListHeaderComponent = { this.FlatListHeader }
ItemSeparatorComponent = { this.FlatListItemSeparator}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) => <ArticleItem article = { item } />}
/>
</View>
);
}
const SplashScreen = (props) => {
return (
<View style = { styles.container } >
<ImageBackground style= { styles.backgroundImage } source={{uri: 'http://i.imgur.com/IGlBYaC.jpg'}} >
<View style= { styles.logoContainer }>
<Text style = { styles.logoText }>
Newzzz
</Text>
<Text style = { styles.logoDescription }>
Get your doze of daily news!
</Text>
</View>
</ImageBackground>
</View>
);
}
const App = () => {
const URL = 'https://raw.githubusercontent.com/nimramubashir/React-Native/fetch/articles.json';
const [articles, setArticles] = useState([]);
const [loading, setLoading ] = useState(true);
useEffect(()=>{
fetch(URL)
.then((response) => response.json())
.then((responseJson) => {
return responseJson.articles;
})
.then( articles => {
setArticles(articles);
console.log(articles);
setLoading(false);
})
.catch( error => {
console.error(error);
});
} , []);
if (loading){
return <SplashScreen />
} else {
return <HomeScreen articles = { articles }/>
}
};
export default App
The code is the same as the tutorial, but when I'm trying to run this code, I'm getting an Error
ReferenceError: FlatListItemSeparator is not defined
I've tried to import the FlatListItemSeparator, but since it is read-only, I can't. I'm getting this error at both FlatListItemSeparator and FlatListHeader. Why am I getting this error, and how can I solve it?
you are having each component as separate Function-Component. The tutorial is probably based on Class-Components. In Function-Components there is no this, so just remove the this.
I want to navigate from my login screen to the home screen without showing the view. I am trying to do is if from the splash screen if it gets the username from async storage then move to login page ...wherein login page by if the username matches from the POST method in login screen directly login if not then show the login screen view
here is my code
import React ,{useState} from 'react';
import {
View,
Text,
TouchableOpacity,
TextInput,
Platform,
StyleSheet ,
StatusBar,
Alert
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import LinearGradient from 'react-native-linear-gradient';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import Feather from 'react-native-vector-icons/Feather';
import { useTheme } from 'react-native-paper';
const asdf = ({navigation}) => {
const STORAGE_KEY = 'username';
const [userName, setUserName ] = useState('');
const [errortext, setErrortext] = useState('');
const retrieveData = async () => {
try {
const value = await AsyncStorage.getItem(STORAGE_KEY);
if (value !== null) {
var str = value;
// str = str.replace(/^"|"$/g, '');
str = str.replace(/"/g,'');
fetchData(str);
}
} catch (error) {
// Error retrieving data
}
};
retrieveData();
const handleSubmitPress = () => {
if (!userName){
setUserName('')
// onChangeText();
return
} else{
fetchData(userName);
}
setUserName('')
//onChangeText();
}
const fetchData = (userName) => {
if(userName){
let dataToSend = {search :userName}
let formBody = [];
for (let search in dataToSend) {
let encodeKey = encodeURIComponent(search);
let encodeValue = encodeURIComponent(dataToSend[search]);
formBody.push(encodeKey + '=' + encodeValue);
}
formBody = formBody.join('&');
fetch('https://qwert/work/rest/apiofficeapp.php', {
method: 'POST', //Request Type
body: formBody, //post body
headers: {
//Header Defination
'Content-Type':
'application/x-www-form-urlencoded;charset=UTF-8',
},
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson[0] != ''){
//alert(JSON.stringify(responseJson[0]));
const saveData = async () => {
try {
await AsyncStorage.setItem(STORAGE_KEY, responseJson[0][0]['username'])
//await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(responseJson[0][0]['username']))
//alert('Data successfully saved login page')
} catch (e) {
//alert('Failed to save the data to the storage')
}
}
saveData();
navigation.navigate('HomeApp');
setErrortext('');
}else {
setErrortext(userName + 'user not found')
}
})
.catch((error) => {
console.error(error);
});
} }
// const onChangeText = userName => setUserName(userName)
const onChangeText = userName => setUserName(userName)
const { colors } = useTheme();
// const onChangeText = (val) => {
// if( val.length !== 0 ) {
// setUserName({
// ...userName,
// userName: val,
// });
// } else {
// setUserName({
// ...userName,
// userName: val,
// });
// }
// }
return (
<View style={styles.container}>
<StatusBar backgroundColor='#009387' barStyle="light-content"/>
<View style={styles.header}>
<Text style={styles.text_header}>Welcome!</Text>
</View>
<Animatable.View
animation="fadeInUpBig"
style={[styles.footer, {
backgroundColor: colors.background
}]}
>
<Text style={[styles.text_footer, {
color: colors.text
}]}>Username</Text>
<View style={styles.action}>
<FontAwesome
name="user-o"
color={colors.text}
size={20}
/>
<TextInput
placeholder="Your Username"
placeholderTextColor="#666666"
style={[styles.textInput, {
color: colors.text
}]}
autoCapitalize="none"
onChangeText={(userName) => onChangeText(userName)}
onSubmitEditing={handleSubmitPress}
/>
</View>
{/* {data.check_textInputChange ?
<Animatable.View
animation="bounceIn"
>
<Feather
name="check-circle"
color="red"
size={20}
/>
</Animatable.View>
: null}
</View> */}
<View>
{errortext != '' ? (
<Text style={styles.errorMsg}>
{errortext}
</Text>
) : null}
</View>
<View style={styles.button}>
<TouchableOpacity
style={styles.signIn}
onPress={() => {handleSubmitPress()}}
>
<LinearGradient
colors={['#eb0c00', '#A80900']}
style={styles.signIn}
>
<Text style={[styles.textSign, {
color:'#fff'
}]}> Sign In </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={() => navigation.navigate('Register')}
style={[styles.signIn, {
borderColor: '#A80900',
borderWidth: 1,
marginTop: 15
}]}
>
<Text style={[styles.textSign, {
color: '#A80900'
}]}> Register </Text>
</TouchableOpacity>
</View>
</Animatable.View>
</View>
);
};
export default asdf;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#A80900'
},
header: {
flex: 1,
justifyContent: 'flex-end',
paddingHorizontal: 20,
paddingBottom: 50
},
footer: {
flex: 3,
backgroundColor: '#fff',
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
paddingHorizontal: 20,
paddingVertical: 30
},
text_header: {
color: '#fff',
fontWeight: 'bold',
fontSize: 30
},
text_footer: {
color: '#05375a',
fontSize: 18
},
action: {
flexDirection: 'row',
marginTop: 10,
borderBottomWidth: 1,
borderBottomColor: '#f2f2f2',
paddingBottom: 5
},
actionError: {
flexDirection: 'row',
marginTop: 10,
borderBottomWidth: 1,
borderBottomColor: '#FF0000',
paddingBottom: 5
},
textInput: {
flex: 1,
marginTop: Platform.OS === 'ios' ? 0 : -12,
paddingLeft: 10,
color: '#05375a',
},
errorMsg: {
color: '#FF0000',
fontSize: 14,
},
button: {
alignItems: 'center',
marginTop: 50
},
signIn: {
width: '100%',
height: 50,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10
},
textSign: {
fontSize: 18,
fontWeight: 'bold'
}
});
I not able to navigate to home app without showing the login screen directly
One thing you can try is to use a Splash lib that will create an actual native screen for the splash and you just dismiss the splash screen on the login screen or the main screen.
One lib you may use:
https://github.com/crazycodeboy/react-native-splash-screen
It fairly simple to install and you just need to call this on your Login or Mais screen when its mounted:
import SplashScreen from 'react-native-splash-screen'
export default class MainPage extends Component {
componentDidMount() {
SplashScreen.hide();
}
}
Success on your project.
I'm having an issue with the "onLogin" function within the "LoginComponent". After pressing the TouchableOpacity that handles that function, I want the user to then be directed to the "HomeComponent", but instead I get this console.error: "the action navigate with payload...was not handled..." Anybody know why this is? Any help would be greatly appreciated. Thanks!
import React, { Component } from 'react';
import 'react-native-gesture-handler';
import { createStackNavigator } from '#react-navigation/stack';
import WelcomeScreen from './WelcomeComponent';
import LoginScreen from './LoginComponent';
import RegisterScreen from './RegisterComponent';
import HomeScreen from './HomeComponent';
import { NavigationContainer } from '#react-navigation/native';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import { AsyncStorage } from 'react-native';
const AuthStack = createStackNavigator();
const AuthStackScreen = () => {
return <AuthStack.Navigator initialRouteName="Welcome">
<AuthStack.Screen name="Welcome" component={WelcomeScreen} />
<AuthStack.Screen name="Login" component={LoginScreen} />
<AuthStack.Screen name="Register" component={RegisterScreen} />
</AuthStack.Navigator>
};
const HomeTab = createMaterialBottomTabNavigator();
const HomeTabScreen = () => {
return <HomeTab.Navigator initialRouteName="Home">
<HomeTab.Screen name="Home" component={HomeScreen} />
</HomeTab.Navigator>
}
class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false,
};
this.loginStatusCheck();
}
loginStatusCheck = async () => {
const userToken = await AsyncStorage.getItem("userprofile");
if(userToken) {
this.setState({ isLoggedIn: true })
} else {
this.setState({ isLoggedIn: false })
}
}
render() {
return(
<NavigationContainer>
{this.state.isLoggedIn ? <AuthStackScreen /> : <HomeTabScreen />}
</NavigationContainer>
);
};
};
export default Navigation;
import React, { Component } from 'react';
import { StyleSheet, SafeAreaView, ScrollView, View, TouchableOpacity, Text, Linking, AsyncStorage } from 'react-native';
import { Input, CheckBox } from 'react-native-elements';
import { FontAwesome } from '#expo/vector-icons';
class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password:"",
token: "",
remember: false
};
this.getData();
};
handleUsernameChange = username => {
this.setState({ username })
};
handlePasswordChange = password => {
this.setState({ password })
};
onLogin = async () => {
try {
await AsyncStorage.setItem("userprofile", JSON.stringify({ username: this.state.username, password: this.state.password }));
this.props.navigation.navigate("Home", {
screen: "HomeScreen",
});
} catch (err) {
console.log(err);
}
};
getData = async () => {
try {
const userprofile = await AsyncStorage.getItem("userprofile");
const userProfile = JSON.parse(userprofile);
if (userProfile !== null) {
this.setState({ ...userProfile })
}
if (username !== null) {
this.setState({ username })
}
if (password !== null) {
this.setState({ password })
}
} catch (err) {
console.log(err);
}
}
render() {
const { username, password } = this.state;
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<Text style={styles.titleText}>Login</Text>
<Text style={styles.fillerText}>Hi there! Nice to see you again.</Text>
<Input
inputStyle={{color: 'white'}}
placeholder="Enter username"
onChangeText={this.handleUsernameChange}
value={username}
keyboardType="email-address"
autoCapitalize="none"
leftIcon={{ type: 'font-awesome', name: 'user-circle-o', color: 'white', marginRight: 10 }}
/>
<Input
inputStyle={{color: 'white'}}
placeholder="Password"
secureTextEntry
onChangeText={this.handlePasswordChange}
value={password}
leftIcon={{ type: 'font-awesome', name: 'lock', color: 'white', marginRight: 10 }}
/>
<CheckBox
title="Remember Me"
checked={this.state.remember}
onPress={() => this.setState({remember: !this.state.remember})}
containerStyle={styles.rememberCheckbox}
textStyle={{color: 'white'}}
checkedColor="crimson"
/>
<TouchableOpacity
style={styles.loginButton}
title="Login" type="submit"
onPress={this.onLogin}
>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
<Text style={{textAlign: 'center', color: 'grey', marginTop: 20}}>
OR use an account from one of the following:
</Text>
<View style={styles.buttonsContainer}>
<TouchableOpacity style={styles.twitterButton}>
<FontAwesome name="twitter" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Twitter</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.facebookButton}>
<FontAwesome name="facebook-square" color="white" style={{marginRight: 5}}/>
<Text style={{color: 'white'}}>Facebook</Text>
</TouchableOpacity>
</View>
<View style={{alignItems: 'center'}}>
<TouchableOpacity style={styles.googleButton}>
<FontAwesome name="google" color="black" style={{marginRight: 5}}/>
<Text style={{color: 'grey'}}>Google</Text>
</TouchableOpacity>
</View>
<View style={styles.linkContainer}>
<TouchableOpacity style={{marginTop: 75}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Forgot Your Password?
</Text>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: 75, marginLeft: 210}} onPress={() => Linking.openURL('#')}>
<Text style={{color: 'white'}}>
Register
</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
);
};
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'black'
},
buttonsContainer: {
flex: 2,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row'
},
linkContainer: {
flex: 3,
justifyContent: 'center',
flexDirection: 'row'
},
titleText: {
fontSize: 26,
color: 'white',
marginBottom: 30,
marginTop: 20
},
fillerText: {
color: 'grey',
marginBottom: 20
},
loginButton: {
backgroundColor: 'crimson',
paddingVertical: 17,
paddingHorizontal: 25,
borderRadius: 20,
textAlign: 'center'
},
buttonText: {
color: 'white',
fontSize: 18,
textAlign: 'center'
},
twitterButton: {
backgroundColor: '#00acee',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
facebookButton: {
backgroundColor: '#4267B2',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
googleButton: {
backgroundColor: '#FFFFFF',
marginTop: 20,
padding: 10,
justifyContent: 'center',
alignItems: 'center',
width: '40%',
marginLeft: 20,
flexDirection: 'row',
borderRadius: 20
},
rememberCheckbox: {
margin: 10,
marginBottom: 20,
backgroundColor: null
}
});
export default LoginScreen;
I don't think its necessary to use navigate in your LoginScreen component, since you've already written code that conditionally renders two navigators based on the value of isLoggedIn.
What you're missing in your current implementation is a way to update isLoggedIn from within your LoginScreen component. Then if isLoggedIn is updated and set to true, the Navigation component will be re-rendered and the HomeScreen component is shown without having to navigate.
I've chosen to use react context here, but you could also use this approach with something like redux also if you prefer that. The reason to use something like react context is to be able to easily pass isLoggedIn and its setter between components.
I'll give a more general example, because its easier to illustrate the approach that way:
// Imports and other stuff...
const LoginContext = React.createContext([null, () => {}]);
const LoginContextProvider = props => {
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
return (
<LoginContext.Provider value={[isLoggedIn, setIsLoggedIn]}>
{props.children}
</LoginContext.Provider>
);
};
const HomeScreen = () => {
return (
<View>
<Text>HomeScreen</Text>
</View>
);
};
const LoginScreen = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<View>
<Text>LoginScreen</Text>
<Button
title="login"
onPress={() => {
setIsLoggedIn(true);
}}
/>
</View>
);
};
const HomeTabScreen = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
</Tab.Navigator>
);
};
const AuthStackScreen = ({ navigation }) => {
return (
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
);
};
const Navigation = () => {
const [isLoggedIn, setIsLoggedIn] = React.useContext(LoginContext);
return (
<NavigationContainer>
{isLoggedIn ? <HomeTabScreen /> : <AuthStackScreen />}
</NavigationContainer>
);
};
export default function App() {
return (
<LoginContextProvider>
<Navigation />
</LoginContextProvider>
);
}
So the approach shown above is to create a provider that holds your isLoggedIn state and setter (setIsLoggedIn). Then when we wrap Navigation with this provider so we can access isLogged and setIsLoggedIn from any component inside the provider, allowing us to update the isLogged state inside the LoginScreen component. When this state updates, the provider and everything inside it (i.e. Navigation), will re-render and show the HomeScreen component.
Normally the convention is to put most the react context related stuff in its own file and import parts in components where you need them, but for demonstration purposes I haven't done this.