So i'm building a very simple mobile app that fetches clients data .so far everything is working fine. The only problem i keep encountering is rendering Flatlist data using api sauce. My api call is successful, i receive all the data from the database. When i reload expo the data doesn’t show yet when i hit save ‘cmd + s’ of my code the data get displayed successfully displayed. So i don’t understand why my data doesn’t get rendered when the component get mounted. here's my code
// i built hook for my api calls
import useApi from "../../hooks/useApi";
const getFoldersApi = useApi(foldersApi.getFolders);
const [foldersList, setFoldersList] = useState([]);
useEffect(() => {
getFoldersApi.request();
setFoldersList(getFoldersApi.data);
}, []);
<FlatList
style={styles.folders}
/// here reside the problem
data={foldersList}
keyExtractor={(folder) => folder.Guid}
renderItem={({ item, index }) => (
<Card
title={item.Nom}
image={folderIcon}
index={index}
folderType={item.TypeDossier}
folderState={item.EtatDossier}
depositDate={item.DatedepoDossier}
shippingType={item.TypeManifeste}
vendor={item.Fournisseur}
onPress={() => navigation.navigate("Détails", item)}
/>
)}
/>
my api hook
import { useState } from "react";
export default useApi = (apiFunc) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const request = async (...args) => {
setLoading(true);
const response = await apiFunc(...args);
setLoading(false);
if (!response.ok) return setError(true);
setError(false);
setData(response.data);
};
return { data, error, loading, request };
};
here's what i mean if any of you didn't understand my problem
Related
I a creating a simple reactive app. I have implemented a fetch from an open API and it all works fine.
But when I change the url of that api in the fetch to an api that needs an api key to access it stops working. I have my own api key and have followed the instructions on the api documentation.
This is the api:
https://calendarific.com/api-documentation
I have a Holidays Component and an App.js document.
If I use the coffee API in my component everything is displayed properly.
`
import React, { useState, useEffect } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Text } from "native-base";
export default function Holidays() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
//fetching the data from the API
//data Hook willhold fetched data
//loading hook will tell the user if the data is on its way
const fetchData = async () => {
const resp = await fetch("https://api.sampleapis.com/coffee/hot");
const data = await resp.json();
setData(data);
setLoading(false);
};
const renderItem = ({ item }) => {
return (
<Box px={5} py={2} rounded="md" bg="primary.300" my={2}>
{item.title}
</Box>
);
};
useEffect(() => {
fetchData();
}, []);
return (
<NativeBaseProvider>
<Center flex={1}>
<Box> Fetch API</Box>
{loading && <Box>Loading..</Box>}
{data && (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}`
However if I change the url in fetch to the following one I get an error on the console log.
"curl 'https://calendarific.com/api/v2/holidays?&api_key=cb1e68dec32b35d42671b82368aaf2fab927556a' "
The error is the one displayed here:
`**`VM79:1 Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON`**`
I created a barcode scanner App using expo-barcode-scanner.
I have some problems.
The purpose of the scanner is to get the barcode number and send it to barcode.monster and get product details. It works, but I have two main problems which I dont know what should I look for and how to resolve.
After the scanner get a barcode, I want to send to a confirmation screen, where the User should add the product into a category.
const handleBarCodeScanned = ({ type, data }) => {
reqForProduct(data);
setScanned(true);
setText(data);
navigation.navigate('Confirmation');
};
The function above is executed when the barcode camera find a number.
const reqForProduct = async barcode => {
try {
const Product = await axios.get(`https://barcode.monster/api/${barcode}`);
console.log(Product.data);
} catch (error) {
console.log(error);
}
}
The function above is responsible to get the product data.
THE NAVIGATION WORKS, BUT IF I PRESS THE BACK BUTTON AFTER THE FUNCTION SEND ME TO THE CONFIRMATION SCREEN, I CANNOT RESCAN OTHER BARCODE UNLESS I PRESS R (RELOAD) IN THE CONSOLE... THIS IS MY FIRST PROBLEM. Moreover, after coming back to the screen, the console is stucked with the last product fetched from the api.
The second problem is is to transfer the data fetched to the confirmation screen. I tried with the navigation prop like navigation.navigate('Confirmation', {fetchedDataObj} but is not working....
<Stack.Screen
name='Confirmation'
component={AddToContainerScreen} />
THE FULL PAGE CODE BELLOW ----------------------------------------------------
import {View, Text, Button, StyleSheet} from 'react-native';
import {useState, useEffect} from 'react';
import { BarCodeScanner } from 'expo-barcode-scanner';
import axios from 'axios';
const Scanner = ({navigation}) => {
const [permission, setPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [text, setText] = useState('');
const permissionCamera = () => {
( async () => {
const {status} = await BarCodeScanner.requestPermissionsAsync();
setPermission(status == 'granted');
})()
}
const reqForProduct = async barcode => {
try {
const Product = await axios.get(`https://barcode.monster/api/${barcode}`);
console.log(Product.data);
} catch (error) {
console.log(error);
}
}
// Execute permission
useEffect(() => {
permissionCamera();
}, []);
const handleBarCodeScanned = ({ type, data }) => {
reqForProduct(data);
setScanned(true);
setText(data);
navigation.navigate('Confirmation');
};
if (!permission) {
return (
<View>
<Text>Requesting camera permission</Text>
</View>
)
}
return (
<View style={styles.wrapper}>
<BarCodeScanner
style={StyleSheet.absoluteFill}
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
/>
</View>
)
};
const styles = StyleSheet.create({
wrapper: {
flex: 1
}
})
export default Scanner;
Can someone please help me?
BTW THE PRODUCT DATA FROM tHE API COMES SLOWeR THAN the APP MOVES TO THE CONFIRMATION SCREEN...
Problem 1: I think you need to reinitialize it on a focus even listener or something.
useEffect(() => {
permissionCamera();
}, []);
since useEffect() is basically a componentOnMount and it only fires the first time you load the page. When you navigate back this is not gonna fire. Please check if this is the case. You can do a simple log to confirm this.
For the 2nd problem, I can't help you much since there is only very little data. If you really need help, you could dm me on skype. I'll be glad to help you out.
I want to useQuery renders whenever the state changes
is there any option in useQuery hook
`export const Search = ({ navigation }) => {
const [search, setSearch] = useState();
const [dismiss, setDismiss] = useState(false);
const [searchResult, setSearchResult] = useState();
const searchHander = (query) => {
setSearch(query)
setDismiss(true)
}
const searching = useQuery(['searching', search], () => api.search(search));
useMemo(() => {
setSearchResult(searching?.data ? searching?.data?.results : []);
}, [searching?.data])
const searchResults = ({ item }) => {
return <View style={{ marginVertical: 10 }}><SearchResults navigation={navigation} data={item} /></View>
}
const desmiss = useRef(null);
return (...)}`
useQuery is not depend to state
I don't fully understand the question:
I want to useQuery renders whenever the state changes
I'm just assuming you want to refetch when the state changes, because when state changes, your component does render.
For this, all you need to do is add search to the queryKey, which you have already done.
Further, I can see that you are calling setSearchResults in useMemo which is a) unnecessary because react-query already gives you the result and b) violates component purity because you call setState during render.
I think the component should just be:
const [search, setSearch] = useState();
const [dismiss, setDismiss] = useState(false);
const [searchResult, setSearchResult] = useState();
const searchHander = (query) => {
setSearch(query)
setDismiss(true)
}
const searching = useQuery(['searching', search], () => api.search(search));
const searchResult = searching?.data?.results ?? []
Then you can work with searchResult, and whenever setSearch is called, your query will refetch.
I am really newReact Native Testing Library. My app basically works like this: it fetched the data and display on my to my as Text format, I used jsonplace holder api. This is app-demo. I have have created one Text where I define test role="header". I want to test the Text, does it work properly under role="header". I make a fake data and try to test it. I can able target the role from the component but I don't how to get the expected data. I tried with toBe, getByText but each time I am getting error: TypeError: toBe is not function.
This is my app component
const [state, setState] = React.useState([]);
React.useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/")
.then((response) => response.json())
.then((json) => setState(json));
}, []);
return (
<View style={styles.container}>
{state.map((i) => (
<Text role:'header'>{i.title}</Text>
))}
</View>
);
}
This is my test suite
import React from 'react';
import { fireEvent, render, cleanup, act } from '#testing-library/react-native';
import Json from './Json';
describe('<Json/>', () => {
afterEach(cleanup);
test('get data properly', async () => {
const component = <Json/>;
const { getByA11yRole } = render(component);
const header = await getByA11yRole('header');
console.log(header);
expect(header).toBe(/delectus aut autem/);
});
});
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.