I am trying to develop a mobile app with React Native using Firestore as a database. I'm trying to update a specific document when the "handleLike" function is called. I've passed the id of the posts through handleLike function. I'm trying to update the "comment" field for the sake of the trial. The problem is it updates all of the documents in the database. Also handleLike function is called without me pressing the like button whenever I refresh the page. I get that it is in a loop but I couldn't figure out what I'm doing wrong. I would very much appreciate your help. I have added screenshots of the database and the console.
import { React, useState, useEffect } from "react";
import {
View,
Text,
StyleSheet,
Image,
FlatList,
TouchableOpacity,
} from "react-native";
import { Ionicons, MaterialIcons } from "#expo/vector-icons";
import { useNavigation } from "#react-navigation/core";
import { auth, storage, firestore,firebase } from "../firebase";
import { preventAutoHideAsync } from "expo-splash-screen";
import moment from 'moment';
function Feed() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [userData, setUserData] = useState(null);
//const [deleted, setDeleted] = useState(false);
const fetchPosts = async () => {
try {
const list = [];
const profileRef = firestore.collection("users").doc(auth.currentUser.uid);
const doc = await profileRef.get();
await firestore
.collection("posts")
.orderBy('postTime', 'desc')
.get()
.then((querySnapshot) => {
console.log("Total Posts: ", querySnapshot.size);
querySnapshot.forEach((doc) => {
const pId = doc.id
const {
userId,
userName,
userSurname,
post,
postImg,
postTime,
userImg,
likes,
comments,
likeByUsers } = doc.data();
list.push({
id: pId,
userId,
userName,
userSurname,
userImg:userImg,
post,
postImg,
postTime: postTime,
liked: false,
likes,
comments,
likeByUsers,
});
});
});
setPosts(list);
if (loading) {
setLoading(false);
}
console.log("Posts: ", posts);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
fetchPosts();
}, []);
const renderPost = (posts) => {
const handleLike = (id) => {
console.log(id)
firestore.collection('posts')
.doc(id)
.update({
comment: "tryout 2"
})
}
return (
<View style={styles.feedItem}>
<Image source={{uri: posts.userImg}} style={styles.avatar} />
<View style={{ flex: 1 }}>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<View>
<Text style={styles.name}>{posts.userName} {posts.userSurname}</Text>
<Text style={styles.timestamp}>{moment(posts.postTime.toDate()).fromNow()}</Text>
</View>
<MaterialIcons name="expand-more" size={24} color="#73788B" />
</View>
<Text style={styles.post}>{posts.id}</Text>
<Image
source={{uri: posts.postImg}}
style={styles.postImage}
resizeMode="cover"
/>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity onPress={handleLike(posts.id)}>
<Ionicons
name="heart-outline"
size={24}
color="#73788B"
style={{ marginRight: 16 }}
/>
</TouchableOpacity>
<Ionicons name="chatbox-outline" size={24} color="#73788B" />
</View>
</View>
</View>
);
};
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>Feed</Text>
<TouchableOpacity style={styles.addButton}>
<Ionicons name="add-circle" size={32} color="black" />
</TouchableOpacity>
</View>
<FlatList
style={styles.feed}
data={posts}
renderItem={({ item }) => renderPost(item)}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
></FlatList>
</View>
);
}
const styles = StyleSheet.create({
addButton: {
position: "absolute",
right: 30,
top: 60,
},
container: {
flex: 1,
backgroundColor: "#EBECF4",
},
header: {
paddingTop: 64,
paddingBottom: 16,
backgroundColor: "#FFF",
alignItems: "center",
justifyContent: "center",
borderBottomWidth: 1,
borderBottomColor: "#EBECF4",
shadowColor: "#454D65",
shadowOffset: { height: 5 },
shadowRadius: 15,
shadowOpacity: 0.2,
zIndex: 10,
},
headerTitle: {
fontSize: 20,
fontWeight: "500",
},
feed: {
marginHorizontal: 16,
},
feedItem: {
backgroundColor: "#FFF",
borderRadius: 5,
padding: 8,
flexDirection: "row",
marginVertical: 8,
},
avatar: {
width: 36,
height: 36,
borderRadius: 18,
marginRight: 16,
},
name: {
fontSize: 15,
fontWeight: "500",
color: "#454D65",
},
surname: {
fontSize: 15,
fontWeight: "500",
color: "#454D65",
},
timestamp: {
fontSize: 12,
color: "#808588",
marginTop: 4,
},
post: {
marginTop: 16,
fontSize: 14,
color: "#838899",
},
postImage: {
width: 267,
height: 150,
borderRadius: 5,
marginVertical: 16,
},
});
export default Feed;
Console Screenshot:
Firestore Database Screenshot:
Related
i got this problem when i try to save all date in firebase realTime Database pressing submit.
ERROR TypeError: undefined is not an object (evaluating '_app.default.initializeApp')
import firebase from 'firebase';
import React, { useState } from 'react';
import { View, Text, Modal, TouchableOpacity, FlatList, StyleSheet, DatePickerIOS, Image } from 'react-native';
import { Picker } from '#react-native-picker/picker';
const App = () => {
const [chosenDate, setChosenDate] = useState(new Date());
const [selectedValue, setSelectedValue] = useState('Alege Specializarea');
const [selectedDoctor, setSelectedDoctor] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [showPicker, setShowPicker] = useState(false);
const [showButtons, setShowButtons] = useState(false);
const options = ['Alege Specializarea', 'Cardiologie', 'Dermatologie', 'Oftalmologie', 'Analize Medicale'];
const optionMapping = {
'Alege Specializarea': [],
'Cardiologie': ['Dr. Alex', 'Dr. Balut'],
'Dermatologie': ['Dr. Chloe', 'Dr. David'],
'Oftalmologie': ['Dr. Emily', 'Dr. Frank'],
'Analize Medicale': ['Dr. Grace', 'Dr. Henry'],
};
const firebaseConfig = {
apiKey: "AIzaSyBhyYCXEaUlXqr83GtcbAfV2fiFooGzm2k",
authDomain: "first-app-7901e.firebaseapp.com",
databaseURL: "https://first-app-7901e-default-rtdb.europe-west1.firebasedatabase.app",
projectId: "first-app-7901e",
storageBucket: "first-app-7901e.appspot.com",
messagingSenderId: "876718439254",
appId: "1:876718439254:web:afe7784b89f066210334f7",
};
firebase.initializeApp(firebaseConfig);
const writeAppointmentData = (appointment) => {
firebase
.database()
.ref('appointments/' + appointment.id)
.set(appointment);
};
// Read data from the database
const readAppointmentData = (appointmentId) => {
return firebase
.database()
.ref('appointments/' + appointmentId)
.once('value')
.then((snapshot) => {
return snapshot.val();
});
};
const handleSubmit = () => {
const appointment = {
date: chosenDate,
specialization: selectedValue,
doctor: selectedDoctor,
};
writeAppointmentData(appointment);
setModalVisible(true);
};
const handleRead = () => {
readAppointmentData(appointmentId).then((appointment) => {
setAppointment(appointment);
});
};
return (
<>
<View style={styles.container}>
<Image source={require('./book.png')} style={styles.image} />
</View>
<View style={styles.container}>
<DatePickerIOS
date={chosenDate}
onDateChange={setChosenDate}
minuteInterval={30}
/>
<TouchableOpacity
style={styles.selectionButton}
onPress={() => setShowPicker(!showPicker)}
>
<Text style={styles.selectionButtonText}>{selectedValue}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.submitButton}
onPress={handleSubmit}
>
<Text style={styles.submitButtonText}>Submit</Text>
</TouchableOpacity>
{showPicker && (
<Picker
selectedValue={selectedValue}
style={styles.picker}
onValueChange={(itemValue) => {
setSelectedValue(itemValue);
setShowButtons(itemValue !== 'Alege Specializarea');
}}
>
{options.map((option) => (
<Picker.Item
label={option}
value={option}
key={option}
/>
))}
</Picker>
)}
{showButtons && optionMapping[selectedValue].length > 0 && (
<View style={styles.buttonContainer}>
{optionMapping[selectedValue].map((buttonName) => (
<TouchableOpacity
style={[
styles.button,
buttonName === selectedDoctor && {
backgroundColor: '#24b6d4',
},
]}
key={buttonName}
onPress={() => setSelectedDoctor(buttonName)}
>
<Text
style={[
styles.buttonText,
buttonName === selectedDoctor && { color: 'white' },
]}
>
{buttonName}
</Text>
</TouchableOpacity>
))}
</View>
)}
</View>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>
Your appointment has been scheduled for{' '}
{chosenDate.toString()} with {selectedDoctor}
</Text>
<TouchableOpacity
style={styles.modalButton}
onPress={() => setModalVisible(false)}
>
<Text style={styles.modalButtonText}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</>
);
};
const styles = StyleSheet.create({
container: {
top: -160,
flex: 1,
width: 350,
justifyContent: 'center',
},
image: {
alignSelf: 'center',
},
selectionButton: {
backgroundColor: 'lightgray',
padding: 10,
borderRadius: 10,
left: 20,
},
selectionButtonText: {
fontSize: 18,
},
picker: {
width: '100%',
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'center',
},
button: {
backgroundColor: '#fff',
borderWidth: 1,
borderColor: '#24b6d4',
borderRadius: 10,
padding: 10,
margin: 10,
width: 120,
},
buttonText: {
color: '#24b6d4',
fontSize: 18,
textAlign: 'center',
},
submitButton: {
backgroundColor: '#24b6d4',
borderRadius: 10,
padding: 10,
margin: 10,
},
submitButtonText: {
color: 'white',
fontSize: 18,
textAlign: 'center',
},
centeredView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 22,
},
modalView: {
margin: 20,
backgroundColor: 'white',
borderRadius: 20,
padding: 35,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
modalText: {
marginBottom: 15,
textAlign: 'center',
},
modalButton: {
backgroundColor: '#24b6d4',
borderRadius: 10,
padding: 10,
margin: 10,
},
modalButtonText: {
color: 'white',
fontSize: 18,
textAlign: 'center',
},
});
export default App;
I use ExpoGO to "export" the project.
I tried many changes at firebase like: import firebase from 'firebase'; and all that changes for import firebase,none of that works but i tried with Firebase JS SDK and still dosent work.
its my first time i create an APP for my study project , i created app of database of movies using TMDB API , and it remain one last step to finish my project , and it's creating WatchList or Plan to Watch , and i have no idea how to make it . please can someone who have idea of how to create it with Async Storage or anything to save watchlist, and where to add it?
I will put my code
this code of Movie screen, and i need a touchableopacity that make save the movie into favorite component
import React, {useEffect, useState} from 'react';
import {
View,
Text,
Image,
Dimensions,
StyleSheet,
Linking,
ImageBackground,
TouchableOpacity,
ScrollView,
FlatList
} from 'react-native';
import {IMAGE_POSTER_URL} from '../config';
import {GET} from '../../Services/API';
import Loader from '../Components/Loader';
import Constants from '../Components/Constants';
import TrendingMovies from '../Components/TrendingMovies';
import TrendingPeople from '../Components/TrendingPeople';
import { createStackNavigator } from "#react-navigation/stack";
import PeopleDetails from '../Components/PeopleDetails.js';
import { LinearGradient } from 'expo-linear-gradient';
import {POSTER_IMAGE} from '../config';
import AsyncStorage from '#react-native-async-storage/async-storage';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const MovieDetails = props => {
const [loading, setLoading] = useState(true);
const [details, setDetails] = useState();
const [favourites, setFavourites] = useState([]);
useEffect(() => {
const getDetails = async () => {
const data = await GET(`/movie/${props.route.params.movieId}`);
setDetails(data);
setLoading(false);
};
getDetails();
}, []);
useEffect(() => {
const getVideo = async () => {
const results = await GET(`/movie/${props.route.params.movieId/videos}`);
setDetails(results);
setLoading(false);
};
getVideo();
}, []);
const getGenre = () => {
return details.genres.map(genre => (
<View >
<Text style={styles.genre}>{genre.name}</Text>
</View>
));
};
return (
<View style={styles.sectionBg}>
{loading ? (
<Loader />
) : (
<View style={{ flex: 1 }} >
<Image
source={{uri: `${IMAGE_POSTER_URL}${details.backdrop_path}`}}
style={styles.imageBg}
/>
<View style={{flexDirection:'row', justifyContent:'space-between', alignItems:'center', marginRight:15, marginTop:10}}>
<TouchableOpacity onPress={() => props.navigation.goBack()}
style={{ marginLeft:20, marginTop: 20, marginBottom:20}}
>
<Image
source={require("../../assets/icons/back.png")}
style={{ width:93/1.4 , height: 50/1.4 }} />
</TouchableOpacity>
<TouchableOpacity
style={{ marginLeft:20, marginTop: 20, marginBottom:20}}
>
<Image
source={require("../../assets/icons/nolicked.png")}
style={{ width:256/5.7 , height: 252/5.7 }} />
</TouchableOpacity>
</View>
<ScrollView style={{ flex:1 ,}} >
<TouchableOpacity onPress={() => {
Linking.openURL('https://www.youtube.com/watch?v=${details.key}');
}}
style={{ marginTop:240, marginLeft: "70%",zIndex:1 }}
>
<Image
source={require("../../assets/icons/youtube.png")}
style={{ width: 75, height: 75}} />
</TouchableOpacity>
<ImageBackground
source={require("../../assets/icons/hmm.png")}
style={{ width:'100%' , height: '84%',zIndex:-1 ,marginTop: -60,marginBottom:20}} >
<View style={{ alignSelf: 'center' , marginTop:40 }} >
<View style={{flexDirection: 'row' }} >
<Image
source={{uri: `${IMAGE_POSTER_URL}${details.poster_path}`}}
style={{ width: 150/1.2 , height: 220/1.2 , borderRadius: 20, marginTop: 40 , marginLeft: 20, zIndex:1 }} />
<View style= {{flexDirection:'column' , }} >
<Text style={styles.detailsMovieTitle}>{details.title}</Text>
<View style={{flexDirection: 'row' , alignItems: 'center', marginLeft: 15 , backgroundColor:'orange' , width:70, marginVertical: 5, borderRadius:10}} >
<Image
source={require("../../assets/icons/star.png")}
style={{ width: 20, height: 20 , marginLeft: 5, marginVertical:8}} />
<Text style= {{color:'#20222A' , fontSize: 18, marginLeft: 6, fontWeight:'bold' ,marginRight: 15}} >{details.vote_average}</Text>
</View>
<View style={{ flexDirection: 'row', width: 80 ,marginTop:25, marginLeft:20}}>
{getGenre()}
</View>
<Text style={{marginLeft: 14,
marginHorizontal:-5,
marginVertical:5,
fontWeight:'bold',
color: '#C3C3C3',
fontSize: 10,}}>{details.runtime} Minutes</Text>
<Text style={{marginLeft: 14,
marginHorizontal:-5,
color: '#C3C3C3',
fontWeight:'bold',
fontSize: 10,}}> Release Date: {details.release_date} </Text>
</View>
</View>
<View style={{marginLeft:15, zIndex:1 , marginBottom:50, marginLeft:20}} >
<Text style={{color:'white', fontSize:16, fontWeight:'bold' , marginBottom: 1,marginLeft: -5}} > Overview </Text>
<Text style={{color: 'white',
fontSize: 12, width:330, marginBottom:15}}>{details.overview}</Text>
<TrendingPeople
title="Actors"
navigation={props.navigation}
url={`/movie/${props.route.params.movieId}/credits`}
isForPage="details"
/>
<View style={{marginLeft: -15, marginTop:10, }} >
<TrendingMovies
title="SIMILAR MOVIES"
navigation={props.navigation}
url={`/movie/${props.route.params.movieId}/similar`}
/>
</View>
</View>
</View>
</ImageBackground>
</ScrollView>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
sectionBg: {
backgroundColor: Constants.baseColor,
height: deviceHeight,
flex:1
},
trendingPeopleImage: {
height: 70,
width: 70,
borderRadius: 500,
},
trendingPeopleName: {
width: 60,
color: Constants.textColor,
fontSize: 12,
textAlign: 'center',
marginTop: 10,
},
trendingPeopleContainer: {
margin: 10,
},
heading: {
fontSize: 12,
color: 'white',
margin: 10,
fontWeight:'bold'
},
posterImage: {
height: 800,
width: 150,
borderRadius: 10,
},
movieTitle: {
color: Constants.textColor,
width: 150,
textAlign: 'center',
marginTop: 5,
fontSize: 20,
fontWeight:'bold'
},
imageBg: {
position: 'absolute', top:0, left:0 ,
width: deviceWidth,
height: 400,
opacity: 0.8
},
detailsMovieTitle: {
fontSize: 20,
width: 180,
fontWeight:'bold',
color: 'white',
marginLeft:15,
marginTop: 35
},
linkContainer: {
backgroundColor: Constants.secondaryColor,
borderRadius: 100,
padding: 10,
width: 45,
marginLeft: 20,
marginTop: -20,
},
overview: {
color: 'white',
marginHorizontal: 10,
textAlign: 'justify',
fontSize: 16,
},
details: {
color: 'white',
fontSize: 11,
marginLeft: 10,
fontWeight: 'bold',
},
detailsContainer: {
display: 'flex',
marginLeft:15
},
genreContainer: {
borderColor: Constants.textColor,
paddingHorizontal: 0,
},
genre: {
width: 50,
marginHorizontal:-5,
fontWeight:'bold',fontWeight:'bold',
color: '#C3C3C3',
marginRight:4,
fontSize: 9,
},
image : {
height: 100,
width: 180,
borderRadius: 15,
paddingHorizontal: 5,
marginTop: 10,
marginLeft: 20
},
Text: {
marginLeft: 20,
color: 'white',
fontWeight: 'bold',
fontSize: 20
},
title: {
marginTop: 10,
width: 150,
textAlign: 'center',
color: 'white',
fontWeight: 'bold',
fontSize: 12
}
});
export default MovieDetails;```
First you create a favorite state
const [ favorites, setFavorites ] = useState([]);
Then you use useEffect to load the favorite from async storage.
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_key')
if(value !== null) {
setFavorites(JSON.parse('#storage_key'));
}
} catch(e) {
// error reading value
}
}
useEffect(() => {
getData();
}, [])
Then you create a touchable component to add to favorites.
<TouchableOpacity onPress={() => addToFavorites('some_id')}>
Add to Favorites
</TouchableOpacity>
Create the add to favorite function
const addToFavorites = async (id) => {
await AsyncStorage.setItem('#storage_key', JSON.stringify([...favorites, id]))
setFavorites([...favorites, id]);
}
More on Asyncstorage usage here - https://react-native-async-storage.github.io/async-storage/docs/usage
When I submit a form in React Native I get the below error undefined is not an object (evaluating 'title.length'). This problem occurs when I submit a form when the Card.js should be rendering the data from the form. I have checked and its getting the data back fine, seems to be a problem with rendering the data that its reading as undefined. After this error the form actually submits successfully and the Card.js displays the data.
Card.js
import React from "react";
import {
StyleSheet,
View,
Text,
ImageBackground,
TouchableOpacity,
} from "react-native";
const Card = (props) => {
const {
navigation,
title,
address,
homeType,
description,
image,
yearBuilt,
price,
id,
} = props;
return (
<TouchableOpacity
onPress={() => props.navigation.navigate("HomeDetail", { houseId: id })}
>
<View style={styles.card}>
<View style={styles.titleContainer}>
<Text style={styles.title}>
{title.length > 30 ? title.slice(0, 30) + "..." : title}
</Text>
</View>
<View style={styles.imageContainer}>
<ImageBackground source={{ uri: image }} style={styles.image}>
<Text style={styles.price}>${price}</Text>
<View style={styles.year}>
<Text style={styles.yearText}>{yearBuilt}</Text>
</View>
</ImageBackground>
</View>
<View style={styles.description}>
<Text style={styles.descriptionText}>
{description.length > 100
? description.slice(0, 100) + "..."
: description}
</Text>
</View>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
card: {
shadowColor: "black",
shadowOpacity: 0.25,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
borderRadius: 10,
backgroundColor: "#ffffff",
elevation: 5,
height: 300,
margin: 10,
},
titleContainer: {
height: "15%",
padding: 10,
},
title: {
fontSize: 18,
fontWeight: "bold",
color: "gray",
},
imageContainer: {
width: "100%",
height: "65%",
overflow: "hidden",
},
image: {
width: "100%",
height: "100%",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-end",
},
price: {
fontSize: 30,
color: "#fff",
margin: 10,
},
year: {
margin: 10,
backgroundColor: "#2652B0",
height: 25,
width: 80,
borderRadius: 5,
},
yearText: {
fontSize: 20,
color: "#fff",
textAlign: "center",
},
description: {
margin: 10,
},
descriptionText: {
fontSize: 16,
color: "gray",
},
});
export default Card;
HomeListScreen.js
import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
Text,
FlatList,
ActivityIndicator,
} from "react-native";
import { FloatingAction } from "react-native-floating-action";
import { useDispatch, useSelector } from "react-redux";
import Card from "../components/Card";
import * as houseAction from "../redux/actions/houseAction";
const HomeListScreen = (props) => {
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(false);
const { houses } = useSelector((state) => state.house);
useEffect(() => {
setIsLoading(true);
dispatch(houseAction.fetchHouses())
.then(() => setIsLoading(false))
.catch(() => setIsLoading(false));
}, [dispatch]);
if (isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" />
</View>
);
}
if (houses.length === 0 && !isLoading) {
return (
<View style={styles.centered}>
<Text>No home found. You could add one!</Text>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={houses}
keyExtractor={(item) => item._id}
renderItem={({ item }) => (
<Card
navigation={props.navigation}
title={item.title}
address={item.address}
homeType={item.homeType}
description={item.description}
price={item.price}
image={item.image}
yearBuilt={item.yearBuilt}
id={item._id}
/>
)}
/>
<FloatingAction
position="right"
animated={false}
showBackground={false}
onPressMain={() => props.navigation.navigate("AddHome")}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
centered: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
export default HomeListScreen;
<Text style={styles.title}>
{ title ? (title.length > 30 ? title.slice(0, 30) + "..." : title):true}
</Text>
Make sure that title is not undefined.
Android app crashes when I open build app. It's happens only when I build app react native async storage. On iOS & Android emulators it's working stability. Help me please!
At first I thought that the problem was that I did not use JSON, but it turned out that I did not. JOHN tried, but nothing came of it. Maybe I am not saving correctly in Async Storage?
import React, { useState, useEffect } from 'react'
import { View, TextInput, StyleSheet, TouchableOpacity, ScrollView } from 'react-native'
import Icon from 'react-native-vector-icons/Octicons'
import BackNavbar from '../components/BackNavbar'
import { colors } from '../theme/theme'
import AsyncStorage from '#react-native-community/async-storage'
import GoalCard from '../components/GoalCard'
export default GoalScreen = ({ navigation }) => {
const STORAGE_KEY = '#data'
function goBack() {
navigation.goBack()
}
const [ goal, setGoal ] = useState([])
const [ goalScore, setGoalScore ] = useState()
const [ goalName, setGoalName ] = useState('')
const addGoal = () => {
setGoal([
... goal,
{
id: Date.now(),
text: goalName,
score: goalScore,
}
])
setGoalName('')
setGoalScore('')
}
const saveData = async (dataSave) => {
try {
await AsyncStorage.setItem(STORAGE_KEY, dataSave)
} catch (e) {
alert('Failed to save the data to the storage')
}
}
const loadData = async () => {
try {
const json = await AsyncStorage.getItem(STORAGE_KEY) || JSON.stringify([])
const loadData = JSON.parse(json)
if (loadData != null) {
setGoal(loadData)
alert(loadData.map())
}
} catch (e) {
alert('Failed to load the data to the storage')
}
}
useEffect(() => {
loadData()
}, [])
useEffect(() => {
saveData(JSON.stringify(goal))
}, [goal])
return (
<View style={styles.container}>
<BackNavbar title='Goals' back={goBack} />
<ScrollView>
{ goal.map( item => <GoalCard key={item.id} {... item} /> ) }
</ScrollView>
<View style={styles.inputView}>
<TextInput
keyboardType = "number-pad"
style={styles.inputTextScore}
value={goalScore}
onChangeText={score => setGoalScore(score)}
/>
<TextInput
style={styles.inputText}
value={goalName}
onChangeText={name => setGoalName(name)}
/>
<TouchableOpacity
style={styles.inputButton}
onPress={addGoal}
>
<Icon name="plus" size={26} color={colors.LIGHT_COLOR} />
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'flex-start',
},
inputView: {
marginTop: 15,
flexDirection: 'row',
width: '80%',
marginBottom: 15,
},
inputText: {
width: '62%',
height: 50,
paddingHorizontal: '5%',
right: 5,
borderRadius: 15,
backgroundColor: '#f2f2f2',
borderColor: colors.BORDER_COLOR,
color: colors.SECOND_COLOR,
borderWidth: 1,
fontSize: 20,
elevation: 3,
fontSize: 16,
},
inputTextScore: {
width: '20%',
height: 50,
marginRight: 10,
paddingHorizontal: '5%',
right: 5,
borderRadius: 15,
backgroundColor: '#f2f2f2',
borderColor: colors.BORDER_COLOR,
borderWidth: 1,
fontSize: 20,
elevation: 3,
color: colors.SECOND_COLOR,
fontWeight: '500',
},
inputButton: {
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 15,
paddingVertical: 10,
borderRadius: 50,
backgroundColor: colors.MAIN_COLOR,
left: 5,
}
})
I am learning react native for the first time for developing android app not IOS one and I was learning from Building a Simple ToDo App With React Native and Firebase tutorial from youtube.But I am getting an error while trying to add items. I get following error
Firebase.push failed: first argument contains an invalid key($$typeof) in property 'restaurant.restaurant_name.targetInst._nativeParent._currentElement'.keys must be non-empty strings and cant contain ".","#","$","/","["
What might be creating this issue?
import React, { Component } from 'react';
import Firebase from 'firebase';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
TextInput,
ListView
} from 'react-native';
class foodOrderSystem extends Component {
constructor(props){
super(props);
const firebaseRef = new Firebase('foodordersystem.firebaseio.com');
console.log(firebaseRef);
this.itemRef = firebaseRef.child('restaurant');
this.state = {
newRestaurant:'',
// estimated_delivery:'',
// description:'',
restaurantSource: new ListView.DataSource({rowHasChanged: (row1,row2) => row1 !== row2})
};
this.restaurant = [ ];
}
componentDidMount() {
this.itemRef.on('child_added', (snap) => {
this.restaurant.push({
id:snap.key(),
text:snap.val()
});
this.setState({
restaurantSource:this.state.restaurantSource.cloneWithRows(this.restaurant)
});
});
this.itemRef.on('child_removed', (snap) => {
this.restaurant = this.restaurant.filter((x) => x.id !== snap.key());
this.setState({
restaurantSource:this.state.restaurantSource.cloneWithRows(this.restaurant)
});
});
}
addRestaurant(){
if(this.state.newRestaurant !== ''){
this.itemRef.push({
restaurant_name: this.state.newRestaurant
});
this.setState({ newRestaurant:''});
}
}
removeRestaurant(rowData){
this.itemRef.child(rowData.id).remove();
}
render() {
return (
<View style={styles.appContainer}>
<View style={styles.titleView}>
<Text style={styles.titleText}>
foodOrderSystem
</Text>
</View>
<View style={styles.inputcontainer}>
<TextInput
style={styles.input}
onChange={(text) => this.setState({newRestaurant:text})}
value={this.state.newRestaurant} />
<TouchableHighlight
style={styles.button}
onPress={ () => this.addRestaurant() }
underlayColor="#00ffff">
<Text style={styles.btnText}>Add</Text>
</TouchableHighlight>
</View>
<ListView
dataSource={this.state.restaurantSource}
renderRow={this.renderRow.bind(this)} />
</View>
);
}
renderRow(rowData){
return(
<TouchableHighlight
underlayColor="#dddddd"
onPress={() => this.removeRestaurant(rowData)}>
<View>
<View style={styles.row}>
<Text style={styles.todoText}>{rowData.text}</Text>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
}
const styles = StyleSheet.create({
appContainer:{
flex: 1
},
titleView:{
backgroundColor: '#48afdb',
paddingTop: 30,
paddingBottom: 10,
flexDirection: 'row'
},
titleText:{
color: '#fff',
textAlign: 'center',
fontWeight: 'bold',
flex: 1,
fontSize: 20,
},
inputcontainer: {
marginTop: 5,
padding: 10,
flexDirection: 'row'
},
button: {
height: 36,
flex: 2,
flexDirection: 'row',
backgroundColor: '#48afdb',
justifyContent: 'center',
color: '#FFFFFF',
borderRadius: 4,
},
btnText: {
fontSize: 18,
color: '#fff',
marginTop: 6,
},
input: {
height: 36,
padding: 4,
marginRight: 5,
flex: 4,
fontSize: 18,
borderWidth: 1,
borderColor: '#48afdb',
borderRadius: 4,
color: '#48BBEC'
},
row: {
flexDirection: 'row',
padding: 12,
height: 44
},
separator: {
height: 1,
backgroundColor: '#CCCCCC',
},
todoText: {
flex: 1,
},
});
AppRegistry.registerComponent('foodOrderSystem', () => foodOrderSystem);
Here is the attachment of error