How to display data from a firebase firestore in React Native - react-native

For the Life of me, I cannot get this to render the data that I pull from the database.
Here is the code
function assetList(){
const [assetL, setAssetL] = useState([]);
const [errors, setErrors] = useState("");
const getAssets = async () =>{
try{
const list = [];
console.log("Break");
db.collection("assets").get().then(function(querySnapshot){
querySnapshot.forEach(function(doc){
list.push(doc.data());
});
});
//problem
setAssetL([...list]);
//problem
console.log("list");
console.log(list);
console.log("AssetL");
console.log
} catch (e) {
setErrors("Failed To Load Data");
}
};
useEffect(() => {
getAssets();
}, []);
console.log(assetL);
return(
<SafeAreaView style = {styles.Heading}>
<View style = {styles.Heading}>
<Text style = {styles.headText}>Asset List</Text>
</View>
<FlatList
data = {assetL}
renderItem={({item}) => <Text>{item.default}</Text>}
/>
</SafeAreaView>
);
}
I have narrowed down to at least the most pressing issue, other than my jank way of throwing this page of the app together, is that the setAssetL isnt actually setting the assetL const. Can anyone explain why this is happening and how to fix it?

For the getAssets function do something like this:
const getAssets = async () =>{
try {
const list = [];
console.log("Break");
db.collection("assets").get().then(function(querySnapshot){
querySnapshot.forEach(function(doc){
list.push(doc.data());
});
setAssetL(list);
});
...
} catch (e) {
setErrors("Failed To Load Data");
}
};
Your code did not work because db.collection("assets").get() function returns a promise and you handle it asynchronously while expecting it to be synchronous.
Here you can read more about async functions

Related

Promise Rejection with axios. try to make HTTP instead of HTTPs [ duplicate ]

I pull data from the API and write it to the application with usestate() when the app runs there are no problems, but after 10-30 seconds I get this error.
Here is my code.
const App = () => {
const [datas, setDatas] = useState([])
const res = async () => {
const response = await axios.get("http://hasanadiguzel.com.tr/api/kurgetir")
setDatas(response.data.TCMB_AnlikKurBilgileri)
}
res()
return (
<SafeAreaView style={style.container}>
<View>
{datas.map((item) => {
return (
<KurCard
title={item.Isim}
alis={item.BanknoteBuying}
satis={item.BanknoteSelling}
/>
)
})}
</View>
</SafeAreaView>
)
}
How can I fix this ?
Hi #n00b,
The problem is with your URL Protocol.
const App = () => {
const [datas, setDatas] = useState([]);
const res = async () => {
try {
const url = "https://hasanadiguzel.com.tr/api/kurgetir";
const response = await axios.get(url);
const data = await response.data;
console.log(data.TCMB_AnlikKurBilgileri); // check you console.
setDatas(response.data.TCMB_AnlikKurBilgileri);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
res();
}, []);
And also check this out:- Codesandbox.
And please read this Stack Overflow discussion for better understanding:- stackoverflow

AsyncStorage issue in react native expo

I can't even tell you how many variations I have tried, tutorials and documentations that I have watched and read, I cannot transfer data from one page to another. Am using react native expo. I have this included in both pages: import AsyncStorage from '#react-native-async-storage/async-storage';.
This is the page I'm trying to set the data:
const ToyDetails = () => {
const [savedName, setSavedName] = useState('')
const addCart = async() => {
setButtonText('ADDED TO CART!')
try {
await AsyncStorage.setItem('saved_name', savedName)
}catch(error){
console.log(error)
}
}
return(
<View>
<Text value={savedName}>{name}</Text>
#{name} is because I am importing the name from a FlatList item
</View>
)
}
And getting that data from another page:
const Cart = () => {
const [savedName, setSavedName] = useState('')
useEffect(()=>{
getData()
}, [])
const getData = () => {
try {
AsyncStorage.getItem('saved_name')
.then((value)=>{
if(value!=null){
setSavedName(value)
}
})
}catch(error){
console.log(error)
}
}
return (
<View>
<Text value={savedName} onChangeText={(value)=>setSavedName(value)}>{savedName}</Text>
</View>
)
}
I can post other variations I have tried if asked, I've tried adding it into a list and importing the list in the second page, I've tried to JSON.stringify the value savedName first (and JSON.parse it), I even tried doing it in the same way I did for FlatList. I'm not even getting any error messages.
in your ToyDetails.js while saving savedName is empty. i changed to name and able to get it on CartScreen
https://snack.expo.dev/7ozHrsOBT check ToyDetails.j file
const addCart = async() => {
setButtonText('ADDED TO CART!')
try {
console.log("savedName",savedName) //saved name is empty here
await AsyncStorage.setItem('saved_name', name)
}catch(error){
console.log('setitem didnt work')
}
}

Continuously updating an array and grabbing its value in search filter bar React Native app?

I will literally rip out my hair from my head because of how long I've been working on this. I cannot figure out why my filterArray (which is updating properly in my console and filtering itself based on the search from the searchUser function) is working but when I output it onto my screen in my App it keeps saying it's empty? I want it to continuously update the way my searchUser function does but I'm not sure how to do this. Should I call searchUser in my big return statement at the end? Otherwise my filterArray shows up as empty (which is what I'm actually trying to output), and response just copies the full name of PDF names and doesn't update on the screen or narrow down my list based on my search (which is what filterArray does). I think this is because my useEffect function runs once and grabs the filterArray when its empty and just keeps it empty and doesn't reinitialize it.
Sorry if this is confusing but I am just losing it. I also dont want the MyComponent function to return the array items as a component, but as a but if I change it my code tells me I cant return things that are text as a list. Please please help.
const searchUser = async (input) => {
var filterArray = [];
//nametoURL is a dictionary that stores a full list of pdf names from Firebase
Object.keys(nameToURL).map((item) => {
if (item.includes(input) && !filterArray.includes(item)) {
filterArray.push(item);
console.log("FOUND A MATCH");
console.log("MATCH IS: ", filterArray);
} else {
console.log("NO MATCH");
}
});
return { filterArray };
};
const Map = ({ navigation }) => {
var [filterArray, setFilterArray] = useState([]);
var [userInput, setInput] = useState([]);
var [] = useState([]);
var [result, setResult] = useState({});
function MyComponent({ response }) {
console.log(response);
return <Text>{Object.values(response)}</Text>;
}
useEffect(() => {
async function fetchData() {
// You can await here
const response = await searchUser(userInput);
setResult(response);
setFilterArray(filterArray);
// ...
}
fetchData();
}, []);
return (
<Container>
<Header searchBar rounded>
<Item>
<Icon name="search" />
<Input
placeholder="Search For A Map (Case Sensitive)..."
onChangeText={(text) => {
searchUser(text), setInput(text);
}}
autoCapitalize="none"
autoCorrect={false}
/>
</Item>
</Header>
<ScrollView>
<Text style={styles.titleStyle}> Camp Map </Text>
<MyComponent response={result} />
</ScrollView>
</Container>
);
};
The problem is that you're no setting the result state with the result from the searchUser call when the text changes. You can declare a function callback and do that there to have a cleaner code.
function MyComponent({ response }) {
console.log(response);
return <Text>{Object.values(response)}</Text>;
}
const Map = ({ navigation }) => {
var [filterArray, setFilterArray] = useState([]);
var [userInput, setInput] = useState([]);
var [] = useState([]);
var [result, setResult] = useState({});
const onChangeText = async (text) => {
setInput(text);
const response = await searchUser(text);
setResult(response);
// not sure when or were you are assigning filterArray though
setFilterArray(filterArray);
}
useEffect(() => {
async function fetchData() {
// You can await here
const response = await searchUser(userInput);
setResult(response);
setFilterArray(filterArray);
// ...
}
fetchData();
}, []);
return (
<Container>
<Header searchBar rounded>
<Item>
<Icon name="search" />
<Input
placeholder="Search For A Map (Case Sensitive)..."
onChangeText={onChangeText}
autoCapitalize="none"
autoCorrect={false}
/>
</Item>
</Header>
<ScrollView>
<Text style={styles.titleStyle}> Camp Map </Text>
<MyComponent response={result} />
</ScrollView>
</Container>
);
};
Making API calls every time the user types is not recommended, you can check out this pattern to debounce the call for usability https://gist.github.com/simonw/c29de00c20fde731243cbac8568a3d7f

Render Data in Cloud Firestore with a ReactJS Hook

How can I render data retrieved from Cloud Firestore using ReactJS native functional component?
I want to do something like this:
const result=[]
db.collection("collection").where("parameter", "==", "value")
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
result.push(doc.data());
});
export default function foo(){
return(
<View>
{result.map((item) =>
<CustomComponent data=item />
)}
</View>
)
}
Obviously the code does not work because the rendering happens before the promise resolving. I have read a lot on the internet. A possible solution is to update the state in the ComponentDidMount, in which the request to db happens.
So my question is, how can I do it with a functional component? Is this the only and best solution? The data which I want to retrieve from Firestore and I want to display not change so fast.
Hers is a code snippet hope it works for you....
const useData = () => {
const [list, setList] = useState([]);
const [loading, setLoading] = useState(false);
const getData = () => {
const data = [];
db.collection('collection')
.where('parameter', '==', 'value')
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
data.push(doc.data());
});
setList(data);
});
};
return [loading, list, getData];
};
export default function App() {
const [loading, list, getData] = useData();
useEffect(() => {
getData();
}, []);
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator />
) : (
{
// renderList
}
)}
</View>
);
}
It might be because you are trying to render an array of data. I suggest taking a look at this good example here. I have added a few examples of ReactJS map that you might find helpful:
render() {
return (<div>
{this.state.people.map((person, index) => (
<p key={index}>Hello, {person.name} from {person.country}!</p>
))}
</div>);
}
this.state.data.map(function(item, i){
console.log('test');
return <li key={i}>Test</li>
})
You might find these tutorials and userguides helpful:
Getting started with Cloud Firestore and React Native.
Create React Native Firebase CRUD App with Firestore.

How to properly use AsyncStorage in a Movie WatchList

First of all,i tried to make a watchlist for movies,a page that contains movies that you add.I can't get understand async storage and how it works within my code.
I've tried different tutorials,but I still don't get to make it work.I tried with the code that official react-native page has on their site,but with no results.
item2ADD = this.props.navigation.getParam('movie');
_retrieveData = async () => {
try {
await AsyncStorage.setItem('#MySuperStore:key', 'I like to save it.');
} catch (error) {
console.warn("data has not been saved");
}
try {
const value = await AsyncStorage.getItem('TASKS');
if (value !== null) {
console.warn("data has been loaded");
console.warn(value);
}
} catch (error) {
console.warn("data has not been loaded");
}
};
constructor(props) {
super(props);
this.state = {
data : [] ,
};
}
async componentDidMount() {
const data = this._retrieveData();
this.setState({ data });
}
render() {
if(this.state.data!==null) {
return (
<View style={styles.container}>
<Text style={styles.title}>Watchlist</Text>
<TouchableOpacity style={styles.backBtn} onPress={() => {
this.props.navigation.goBack()
}}>
<Image style={styles.backIMG} source={menuImages.back}/>
</TouchableOpacity>
<FlatList
data={this.state.data}
numColumns={2}
renderItem={({item}) =>
<View style={styles.fList}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('Details', {movie: item})}>
<Image style={styles.img} source={{uri: item.coverUrl}}/>
</TouchableOpacity>
<Text style={styles.movieTitle}>{item.title}</Text>
<Text
style={styles.movieDate}>{moment.unix(Math.floor(parseInt(item.releaseDate)) / 1000).format("DD/MM/YYYY")}</Text>
</View>
} keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
else
{
return <Text>FAILED TO LOAD</Text>
}
}
}
I just want to know how can I implement AsyncStorage to store my added movies from the item2ADD,it contains only 1 item that i need to store in order to make a watchlist.(the item which contains all details that i need for a movie).
I want to save all the movies with asyncstorage then show them in that flatlist.
I keep getting :
invariant violation tried to get frame for out of range index nan(on android simulator) when i click to add a movie to the list.
I'm not sure what is the problem you are asking but there is a few things that maybe causing the problem.
1- In your function _retrieveData you don't return anything from it.
I'm not sure what you want to return but what you could do is return the value from the AsyncStorage.
_retrieveData = async () => {
try {
await AsyncStorage.setItem('#MySuperStore:key', 'I like to save it.');
} catch (error) {
console.warn("data has not been saved");
}
try {
const value = await AsyncStorage.getItem('TASKS');
if (value !== null) {
console.warn("data has been loaded");
console.warn(value);
}
// returning the value.
return value
} catch (error) {
console.warn("data has not been loaded");
}
};
2- You are setting state with the data from _retrieveData without waiting for it.
In you componentDidMount you set the data from _retrieveData but because it's a promise, you need to use await to get the data
async componentDidMount() {
// added await
const data = await this._retrieveData();
this.setState({ data });
}
3- The data you provide to FlatList needs to be an array.
When you call pass data={this.state.data} to FlatList, it needs to be an array, if it's not an array, you will have several problems.
Make sure that when you return the value from _retrieveData, it's an array.
// value needs to be an array
const value = await AsyncStorage.getItem('TASKS');
You should also notice that to setItem, it need to be parsed to a json, this means doing something like AsyncStorage.setItem('NAME_OF_YOUR_KEY', JSON.stringify(DATA_YOU_WANT_TO_STORE); and to getItem it need to be parsed to a javascript object, this means doing something like
const jsonValue = await AsyncStorage.getItem('NAME_OF_YOUR_KEY');
const value = JSON.parse(jsonValue);