Contents of Firebase Firestore not rendering in my screen - javascript

I'm using react native to create a simple to-do app using Firebase. I used the firestore database. I am able to push the data into Firebase using user inputs. I also tried fetching the data in my screen but I cannot see the data.
dashboard.js ( I want the list of data to be shown here)
export default function Dash(){
const [task, setTask] = useState();
const [taskItems, setTaskItems] = useState([]);
const [loading, setLoading] = useState(true);
const todoCollection = db.collection('todos');
useEffect(() => {
return todoCollection.onSnapshot((querySnapshot) =>{
const list=[];
querySnapshot.forEach(doc => {
const {text, done} = doc.data();
list.push({
id: doc.id,
text,
done,
});
});
setTask(list);
if (loading) {
setLoading(false);
}
});
}, [])
async function addTask() {
await todoCollection.add({
text:task,
done: false,
}).then(()=> {
alert ("Task added Succesfully")
})
setTask('');
Keyboard.dismiss();
setTask(null);
}
const handleTask =()=>{
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
const deleteTask = (index) => {
let itemsCopy = [...taskItems];
itemsCopy.splice(index,1);
setTaskItems(itemsCopy);
}
if (loading) {
return null;
}
return(
<>
<View style = {styles.tasksWrapper}>
<Text style={styles.sectionTitle} > ToDos List </Text>
<View style={{height:30}}></View>
<View style = {styles.items}>
{/* {
taskItems.map((item, index)=> {
return(
<Task text={item} del={deleteTask} i={index} />
)
})
} */}
<FlatList
style={{flex: 1}}
data={task}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Todo {...item} />}
/>
</View>
</View>
<KeyboardAvoidingView behavior={Platform.OS ==="ios"? "padding": "height"}
style={styles.writeTaskWrapper}>
<TextInput style={styles.input} placeholder={'write a task'} value={task} onChangeText={text => setTask(text)}/>
<TouchableOpacity onPress={()=>addTask()}>
<View style={styles.addWrapper}>
<Text style={styles.addText}> + </Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</>
)
}
Todo.js
import React from 'react';
import {db} from '../firebase/fire';
import { List } from 'react-native-paper';
function Todo({ id, text, done }) {
async function toggleComplete() {
await db
.collection('todos')
.doc(id)
.update({
done: !done,
});
}
return (
<List.Item
text={text}
onPress={() => toggleComplete()}
left={props => (
<List.Icon {...props} icon={done ? 'check' : 'cancel'} />
)}
/>
);
}
export default React.memo(Todo);
The app shows no error but the list is not rendering.

Related

how to assign each list item to the same button in react native

this is my
homePage
as you can see I have some items and a button that I use to add them to the chartScreen, which is chartScreen , I'm using context api to store items in cartContext.js where each item has its own key to make things easier but I cannot correlate the logic for how to assign each item to the button so whenever I press the button its own item gets added to the chartScreen.
const CartContext = createContext();
export function CartProvider({ children }){
const [items, setItems] = useState(
[
{
title: "Pınar",
text: "Pınar Klasik Dana Sucuk (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/klasik_dana_sucuk_paket.png")} />,
key: 1,
},
{
text: "Pınar Uzun Sosis (225g)",
pic: <Image
style={styles.image1}
source={require("./Images/pinar_uzun_sosis.png")} />,
key: 2,
},
]
const [store, setStore] = useState([]);
const addToCart = (text) => {
setStore((prevState) => [
...prevState,
text,
]);
}
return (
<CartContext.Provider value={{items,setItems, addToCart, store}}>
{children}
</CartContext.Provider>
)
I found a cheeky way to send a specific item from addButton.js
const AddButton = () => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() => addToCart(items[0])}>
<Text>+</Text>
</TouchableOpacity>
)
}
and in the chartScreen I view it just like this
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
</View>
)}
/>
)
}
this is for sure not even the wrong way to achieve the goal so can you help me?
You can import your button and make it common for all the items, and pass the value to it.
Here is your button code
const AddButton = ({item}) => {
const { items } = useContext(CartContext);
const { addToCart } = useContext(CartContext);
return (
<TouchableOpacity style={styles.button} onPress={() =>
addToCart(item?.text)}>
<Text>+</Text>
</TouchableOpacity>
)
}
Here you can make button for all you item
const ChartScreen = () => {
const { store } = useContext(CartContext);
if(store.length != 0) {
return (
<FlatList
data={store}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemText}>{item.pic} {item.text}</Text>
<AddButton item={item} />
</View>
)}
/>
)
}

Passing Params to Another Page Using React Native

how can I pass my type2 params on DoctorCategory to another page? I tried like these below, but it gets an error said can't find variable: type2
this type2 is the value from firebase
const Home = ({ navigation }) => {
const [categoryDoctor, setCategoryDoctor] = useState([])
useEffect(() => {
Fire.database()
.ref('category_doctor/')
.once('value')
.then(res => {
console.log('data category: ', res.val())
if (res.val()) {
setCategoryDoctor(res.val())
}
})
.catch(err => {
showError(err.message)
})
}, [])
useEffect(() => {
getData('user').then(res => {
console.log('data user:', res)
})
}, [])
return (
<View style={styles.content}>
<Text style={styles.welcome}>How can we help you?</Text>
<View style={styles.category}>
<DoctorCategory
type1='General'
type2={categoryDoctor.categoryA}
pic={ILLDocGen}
onPress={() => navigation.navigate('ChooseDoctor', type2)} //<== this one
/>
</View>
</View>
)}
And I call it on another page using.
const ChooseDoctor = ({navigation, route}) => {
const type = route.params
return (
<View style={styles.container}>
<Header1 type='light' title= {`Select a ${type.type2}`}/>
</View>
)}
you should use props in ChooseDoctor component! use this:
const ChooseDoctor = ({navigation, route, props}) => {
return (
<View style={styles.container}>
<Header1 type='light' title= {`Select a ${props.type2}`}/>
</View>
)}
The 2nd param is an object
onPress={() => navigation.navigate('ChooseDoctor',{
type2
)}
Reference https://reactnavigation.org/docs/params/#passing-params-to-nested-navigators

Loading spinner as well as fetched products from firebase isn't showing until I refresh the screen in react native

I am using ActivityIndicator for showing the loading screen while my dispatch function dispatches the action and fetches the products from the firebase and renders it on my app screens But this is not happening. My app is showing products that are in store as dummy data and if I refresh the screen then it shows the data from firebase but not the loading spinner to show that loading is true.
ProductOverviewScreen.js:
import React, { useState, useEffect, useCallback } from "react";
import {
FlatList,
View,
Button,
Text,
StyleSheet,
Platform,
ActivityIndicator,
} from "react-native";
import { useSelector, useDispatch } from "react-redux";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import ProductItem from "../../components/shop/ProductItem";
import * as cartActions from "../../store/actions/cart";
import * as productActions from "../../store/actions/products";
import CustomHeaderButton from "../../components/UI/HeaderButton";
import Colors from "../../constants/Colors";
const ProductOverviewScreen = (props) => {
const [IsLoading, setIsLoading] = useState();
const [IsRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState();
const products = useSelector((state) => state.products.availableProducts);
const dispatch = useDispatch();
const loadedProducts = useCallback(() => {
setError(null);
setIsRefreshing(true);
dispatch(productActions.fetchProducts())
.then(setIsLoading(false))
.catch((err) => {
setError(err.message);
});
setIsRefreshing(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
const willFocusSub = props.navigation.addListener(
"willFocus",
loadedProducts
);
return () => {
willFocusSub.remove();
};
}, [loadedProducts]);
useEffect(() => {
const loading = async () => {
setIsLoading(true);
await loadedProducts();
setIsLoading(false);
};
}, [dispatch, loadedProducts]);
const selectItemHandler = (id, title) => {
props.navigation.navigate("ProductDetail", {
productId: id,
productTitle: title,
});
};
const addToCartHandler = async (itemData) => {
setIsLoading(true);
await dispatch(cartActions.addToCart(itemData.item));
setIsLoading(false);
};
if (error) {
return (
<View style={styles.loadingSpiner}>
<Text>An Error occurred! </Text>
<Button
title="Try Again"
onPress={loadedProducts}
color={Colors.primary}
/>
</View>
);
}
if (IsLoading) {
return (
<View style={styles.loadingSpiner}>
<ActivityIndicator size="large" color={Colors.primary} />
</View>
);
}
if (!IsLoading && products.length === 0) {
return (
<View style={styles.loadingSpiner}>
<Text>No Product Found!</Text>
</View>
);
}
return (
<FlatList
data={products}
onRefresh={loadedProducts}
refreshing={IsRefreshing}
renderItem={(itemData) => (
<ProductItem
image={itemData.item.imageUrl}
title={itemData.item.title}
price={itemData.item.price}
onSelect={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
>
<Button
color={Colors.primary}
title="View Details"
onPress={() => {
selectItemHandler(itemData.item.id, itemData.item.title);
}}
/>
{IsLoading ? (
<ActivityIndicator size="small" color={Colors.primary} />
) : (
<Button
color={Colors.primary}
title="To Cart"
onPress={() => {
addToCartHandler(itemData);
}}
/>
)}
</ProductItem>
)}
/>
);
};
ProductOverviewScreen.navigationOptions = (navigationData) => {
return {
headerTitle: "All Products",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Menu"
iconName={Platform.OS === "android" ? "md-menu" : "ios-menu"}
color={Platform.OS === "android" ? Colors.primary : "white"}
onPress={() => {
navigationData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Cart"
iconName={Platform.OS === "android" ? "md-cart" : "ios-cart"}
onPress={() => {
navigationData.navigation.navigate("Cart");
}}
/>
</HeaderButtons>
),
};
};
const styles = StyleSheet.create({
loadingSpiner: {
flex: 1,
justifyContent: "center",
alignItems: "center",
opacity: 1,
},
});
export default ProductOverviewScreen;
I have also checked on both emulators IOS and android also on my real device. If I open the app on my real device then instantly app renders the data from the firebase but doesn't show a loading spinner.
In useEffect If I try to add dependency loading which costs async code and a function which fetches the data from firebase then it shows an error saying Can't find variable: loading.
Please making loadedProducts from sync to async

display firebase data on a flatlist

I'm trying to display a bunch of data i have on firebase in a flatlist, I don't really know where the problem is right now, i've tried physically filling the array out and that works but it doesn't when i get the data from firebase. I do see that im getting the data on the console log but it's not getting displayed.
function Squad() {
const gk = [];
db.collection('squad').orderBy('position').get().then(snapshot => {
snapshot.forEach(doc => {
const playerObject = doc.data();
gk.push({name: playerObject.name, number: playerObject.number});
console.log(gk);
});
});
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
You can get the info on mount in an async function, then store it in a stateful array using hooks.
function Squad() {
const [gk, setGk] = useState([]);
const getSquad = async () => {
const ref = db.collection('squad').orderBy('position');
const doc = await ref.get();
const playerObject = doc.data();
const newGk = [...gk, {name: playerObject.name, number: playerObject.number}];
setGk(newGk);
}
useEffect(() => {
getSquad();
}, [])
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>{number} - {name}</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
)
return(
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
)
}
Start by creating a useEffect hook to act as a componentWillMount function to call the method when the compnent is ready. I have also included catch block in order to show any errors that might occur.
import React, { useState, useEffect } from "react";
const Squad = () => {
const [gk, setGK] = useState([]);
useEffect(() => {
getSquadData();
});
const getSquadData = () => {
db.collection("squad")
.orderBy("position")
.get()
.then((snapshot) => {
let myData = [];
snapshot.forEach((doc) => {
const playerObject = doc.data();
myData.push({
id: playerObject.id,
name: playerObject.name,
number: playerObject.number,
});
});
setGK(myData);
})
.catch((error) => {
console.log("Error getting data: ", error);
});
};
const Item = ({ name, number }) => (
<View style={styles.item}>
<Text style={styles.itemText}>
{number} - {name}
</Text>
</View>
);
const renderItem = ({ item }) => (
<Item name={item.name} number={item.number} />
);
return (
<View>
<View style={styles.bar}>
<Text style={styles.barText}>goalkeeper</Text>
</View>
<FlatList
data={gk}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default Squad;
So if you are seeing error logs in your console, check your collection in firestore, and also check the rules in your firestore.

Passing an item ID to a component from keyExtractor

I'm making an app in React Native. There are three components I'm currently concerned with:
AllList.js: A screen comprised of a search bar and a FlatList of RowCard.js instances.
RowCard.js: a custom TouchableHighlight component that displays an item from an API, and displays DrinkPopup.js when tapped by using a state stored in AllList.js.
DrinkPopup.js: A custom Modal component that needs to take an ID from whichever RowCard is tapped and use it to make an API call to get its own data.
I can't figure out how to take the ID from the RowCard or FlatList and pass it to DrinkPopup - how should I do it?
Relevant code for AllList:
export default function AllList() {
const [isLoading, setLoading] = useState(true);
const [drinkData,setDrinkData] = useState([]);
const [searchValue, onChangeText] = useState(''); //needed for search
const [reloading, setReloading] = useState(false);
const [modalVisible, setModalVisible] = useState(false); //normal modal visibility handler
useEffect (() => {
fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' + searchValue)
.then((response) => response.json())
.then((json) => setDrinkData(json.drinks))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
},[drinkData]);
return (
<View style = {styles.screen}>
<View style = {styles.searchSection}>
<TextInput
placeholder="Search Drinks..."
style={styles.input}
onChangeText={text => onChangeText(text)}
value={searchValue}/>
</View>
<FlatList
data={drinkData}
keyExtractor={({ idDrink }, index) => idDrink}
removeClippedSubviews={true}
initialNumToRender={5}
renderItem={({ item }) => (
<RowCard id={item.idDrink} image={item.strDrinkThumb} title={item.strDrink} alcontent={item.strAlcoholic}
ingredient1={item.strIngredient1} ingredient2={item.strIngredient2} ingredient3={item.strIngredient3} setModalVisible={setModalVisible}
/>
)}
extraData={reloading}
/>
<DrinkPopup modalVisible={modalVisible} setModalVisible={setModalVisible}/>
</View>
);
};
Relevant code for RowCard:
const RowCard = (props) => {
return(
<TouchableHighlight
style={styles.rowCard}
activeOpacity={0.6}
underlayColor={"white"}
onPress={() => {props.setModalVisible(true) }}
>
<View style={styles.rowCard}>
<Image source={{uri: props.image, width: 150, height: 150}} />
<View style={styles.textBox}>
<Text style={styles.titleText}>{props.title}</Text>
<Text style={styles.ingredient}> Main ingredients: {props.ingredient1}, {props.ingredient2}, {props.ingredient3} </Text>
</View>
</View>
</TouchableHighlight>
)
};
Relevant code for DrinkPopup:
const DrinkPopup = (props) => {
return(
<Modal isVisible={props.modalVisible}
onBackdropPress={()=>{props.setModalVisible(false)}} //allows closing modal by tapping outside it or back button
onBackButtonPress={()=>{props.setModalVisible(false)}}
animationIn={"slideInUp"}>
<View style={styles.infocard}>
<View style={styles.titleBox}>
<Text style={styles.header}>I HAVE NO IDEA WHAT YOU PICKED</Text>
</View>
</View>
</Modal>
)
}

Categories