Flat list not being rendered in react native - reactjs

In my React native page
Im navigating from one page to another page with parameters
so those parameters has id
which will be used to fetch data from endpoint and display that in flat list
function Assessments ({route,navigation}) {
useEffect(()=>{
fetchData(file)
},[]);
const { file } = route.params;
const [data,setData] = useState([]);
file consists of route params(Id)
and fetchdata function triggers that function with the id and fetches data
const fetchData = async (file) => {
axios.get(`endpoint`)
.then(function (response) {
console.log(response.data)
setData(response.data)
})
.catch(function (error) {
console.log(error);
})
}
and im returning this
return (
<View>
<Text>okay</Text>
<FlatList
flexGrow= {0}
minHeight= '20%'
maxHeight='80%'
data={data}
renderItem={showdata}>
</FlatList>
</View>
)
and renderitem is
const showdata = ({item}) => {
<View>
sdfdsfsdf
</View>
}
but that part isnt even being rendered
not sure where is the issue !
console.log()
{
"id": 19,
"name": "test1",
}
this is how the data from the endpoint is

Your showdata is not returning anything. Please add return to it like this.
Here is the full code.
function Assessments ({route, navigation}) {
const { file } = route.params;
const [data, setData] = useState([]);
useEffect(()=>{
fetchData(file)
},[]);
const fetchData = async (file) => {
axios.get(`endpoint`)
.then(function (response) {
console.log(response.data)
setData(response.data)
})
.catch(function (error) {
console.log(error);
})
}
const showdata = ({ item }) => {
//Add return here
return (
<View>
<Text>
sdfdsfsdf
</Text>
</View>
)
}
return (
<View>
<Text>okay</Text>
<FlatList
//Put all the style within style prop
style={{flexGrow: 0, minHeight: '20%', maxHeight: '80%'}}
data={data}
renderItem={showdata}
>
</FlatList>
</View>
)
}

Related

Cannot get datas on json with flatlist

I am using the Free Meal API with flatlist. I have Category component, Categories page, useFetch hook. I can't see Flatlist on screen. I can get console log of data but I can't reach datas with flatlist.
.env folder:
API_URL_CATEGORIES="https://www.themealdb.com/api/json/v1/1/categories.php"
API_URL_FILTER="https://www.themealdb.com/api/json/v1/1/filter.php?"
useFetch hook for getting the data in URL and returning Loading icon, Error if URL doesn't work and data for data in URL.
function useFetch(url) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState();
const fetchData = async () => {
try {
const {data: responseData} = await axios.get(url);
setData(responseData);
setLoading(false); }
catch (error) {
setError(error.message);
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, []);
return {error, loading, data};
};
export default useFetch;
Category component:
const Category= ({category, onSelect}) => {
return(
<TouchableOpacity style={styles.container} onPress={onSelect}>
<Image
style={styles.image}
source={{uri:category.strCategoryThumb}} />
<Text style={styles.title}>{category.strCategory}</Text>
</TouchableOpacity>
)
}
export default Category;
Categories page:
const Categories = ({navigation}) => {
const { error, loading, data } = useFetch(config.API_URL_CATEGORIES);
console.log(data)
const handleCategorySelect = strCategory => {
navigation.navigate("Detail", {strCategory})
}
const renderCategory = ({item}) => <Category category={item} onSelect={() => handleCategorySelect(item.strCategory)}/>;
if(loading) {
return <Loading/>;
}
if(error) {
return <Error/>;
}
return(
<View style={styles.container}>
<FlatList data={data} renderItem={renderCategory}/>
<Text>Categorises</Text>
</View>
)
}
export default Categories;
I think data is actually object that contains a property categories , which holds an array.
try data.categories and I believe this should work fine.

Invalid use of Hooks when using onPress to call a function

I ran into this issue of Invalid hook call. The AltIconButton is a component that I place in the export default function with redirect={GoogleLogin}
Here is my login.js snippet:
const AltIconButton = (props) => {
console.log(props.name);
return (
<TouchableOpacity activeOpacity={0.5} onPress={props.redirect}>
<MaterialCommunityIcons
style={{
marginHorizontal: 15,
}}
name={props.name}
size={48}
color="white"
/>
</TouchableOpacity>
);
};
Then this is my google_login:
function GoogleLogin() {
const navigation = useNavigation();
const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
expoClientId: Constants.manifest.extra.google.WEB_CLIENT_ID,
});
useEffect(() => {
if (response?.type === "success") {
const { id_token } = response.params;
const credential = Firebase.auth.GoogleAuthProvider.credential(id_token);
Firebase.auth()
.signInWithCredential(credential)
.then(() => {
navigation.replace("Home");
});
}
}, [response]);
return;
}
EDIT:
This is another snippet of where I implement my AltIconButton Component
<View style={styles.bottomBody}>
<AltIconButton name="facebook" redirect={FBLogin}></AltIconButton>
<AltIconButton name="google"redirect={GoogleLogin}></AltIconButton>
</View>
By changing the JS function into its own component solve the problem.
For example:
function GoogleLogin() {
const navigation = useNavigation();
const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
expoClientId: Constants.manifest.extra.google.WEB_CLIENT_ID,
});
useEffect(() => {
if (response?.type === "success") {
const { id_token } = response.params;
const credential = Firebase.auth.GoogleAuthProvider.credential(id_token);
Firebase.auth()
.signInWithCredential(credential)
.then(() => {
navigation.replace("Home");
});
}
}, [response]);
return (
<TouchableOpacity
disabled={!request}
activeOpacity={0.5}
onPress={() => promptAsync()}
/>
);
}

.map function not working with React Native

I have a .map() function with JSX code inside. Although, the JSX is not rendering. It is only rendering after I save the file. I am using expo (React Native).
Here is my code:
import React, { useEffect, useState } from "react";
import * as SecureStore from "expo-secure-store";
import { View, Text, ActivityIndicator } from "react-native";
import { Button } from "react-native-elements";
const Receipts = ({ navigation }) => {
const [receipts, setReceipts] = useState([]);
const [loading, setLoding] = useState(true);
const [result, setResult] = useState({});
const [keys, setKeys] = useState([]);
useEffect(() => {
const getReceiptsData = async () => {
let token = await SecureStore.getItemAsync("token");
console.log(token);
fetch("https://notrealapi/api/receipts", {
method: "GET",
headers: {
Authorization: `JWT ${JSON.parse(token)}`,
},
})
.then((res) => res.json())
.then((json) => {
setReceipts(json);
setLoding(false);
})
.catch((error) => console.error(error));
};
getReceiptsData();
processReceipts();
}, []);
const processReceipts = () => {
const dubps = [];
const resultObj = {};
receipts.map((item) => {
if (dubps.includes(item.merchant_name)) {
resultObj[item.merchant_name] =
resultObj[item.merchant_name] + parseFloat(item.total);
} else {
resultObj[item.merchant_name] = parseFloat(item.total);
dubps.push(item.merchant_name);
}
});
setResult(resultObj);
setKeys(Object.keys(resultObj));
};
const exportReport = async () => {
let token = await SecureStore.getItemAsync("token");
fetch("https://notrealapi/api/export", {
method: "GET",
headers: {
Authorization: `JWT ${JSON.parse(token)}`,
},
})
.then((res) => res.json())
.then((json) => {
console.log(json);
})
.catch((error) => console.error(error));
};
const renderSummary = () => {
return keys.map((key) => {
return (
<View>
<Text
key={key}
style={{
fontSize: 15,
fontWeight: "normal",
paddingBottom: 50,
}}
>
{`You have spent $${result[key].toString()} at ${key}`}
</Text>
</View>
);
});
};
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
{loading ? (
<ActivityIndicator size="large" color="blue" />
) : (
<>
<Text style={{ fontSize: 30, fontWeight: "bold", paddingBottom: 50 }}>
Summary:
</Text>
{renderSummary()}
<Button
type="outline"
title="Export detailed report"
onPress={exportReport}
/>
<Text style={{ fontSize: 10, marginTop: 10 }}>
*The detailed report shall be sent by email.
</Text>
</>
)}
</View>
);
};
export default Receipts;
Note: It does work but only when I save the file and it refreshes using expo CLI. Also, error occurs in the renderSummary() function.
Update: keys can be equal to ["Costco"] and result can be equal to {Costco: 69.99}
You are running processReceipts() before the fetch within getReceiptsData() has resolved.
Notice the order of the console logs in this example.
import React, { useEffect, useState } from "react";
const Receipts = () => {
const [receipts, setReceipts] = useState([]);
const [loading, setLoding] = useState(true);
const [result, setResult] = useState({});
const [keys, setKeys] = useState([]);
useEffect(() => {
const getReceiptsData = async () => {
fetch("https://rickandmortyapi.com/api/character/1", {
method: "GET"
})
.then((res) => res.json())
.then((json) => {
console.log("getReceiptsData resolves");
setReceipts(json);
setLoding(false);
})
.catch((error) => console.error(error));
};
getReceiptsData(); // js won't wait here
processReceipts();
}, []);
const processReceipts = (json) => {
console.log("processReceipts()");
};
return null;
};
export default Receipts;
Instead, handle the data manipulation when the fetch resolves.
import React, { useEffect, useState } from "react";
const Receipts = () => {
const [loading, setLoding] = useState(true);
const [result, setResult] = useState({});
useEffect(() => {
const getReceiptsData = async () => {
fetch("https://rickandmortyapi.com/api/character/1", {
method: "GET"
})
.then((res) => res.json())
.then((json) => {
console.log("getReceiptsData resolves");
processReceipts(json);
setLoding(false);
})
.catch((error) => console.error(error));
};
getReceiptsData();
}, []);
const processReceipts = (json) => {
console.log("processReceipts()");
// do some work and then setResult
};
return null;
};
export default Receipts;
Also, avoid storing a state that is derived from another state where possible. You should either translate the server payload into usable data:
when you receive the payload then set it to state OR
when you are rendering

How to implement infinite list using React Query in react native with Flatlist

Here is my code:
import React, {useState} from 'react';
import {useQuery, useInfiniteQuery} from 'react-query';
import {getMeetup} from '../../api/methods/getMeetups';
export default function MyFunction(props) {
const [next, setNext] = useState('');
const fetchData = async ({pageParam = ''}) => {
const response = await getMeetup( pageParam);
console.log('API RESP', response);
return response;
};
const {data, isLoading, fetchNextPage} = useInfiniteQuery(
'myData',
fetchData,
{
getNextPageParam: (lastPage, pages) => lastPage?.next?._id,
},
);
console.log('RQUERY CHECK', data);
const getMore = () => {
console.log('data end', data?.pages[0]?.next?._id);
fetchNextPage({pageParam: data?.pages[0]?.next?._id});
};
const flattenData = data?.pages
? data?.pages?.flatMap((page) => [...page.Docs])
: [];
return (
<View>
<FlatList
style={{
marginBottom: verticalScale(40),
paddingHorizontal: scale(15),
}}
data={flattenData}
keyExtractor={(item) => item._id}
renderItem={({item, index}) => {
return <ListItem data={item} index={index} />;
}}
onEndReachedThreshold={0.1}
onEndReached={getMore}
/>
</View>
);
}
The problem i am facing is when the page loads the api calls one by one with unique next ids or page param. What i was trying to implement is , when user reaches the end of the page (onEndReached) the data needs to be fetched with a new page param.
getNextPageParam return the value for the next page. So you don't need pass pageParam in fetchNextPage unless you want overwrite, for any reason, the next page value.
You can add a hasNextPage validation for unnecessary requests.
const {data, isLoading, hasNextPage, fetchNextPage} = useInfiniteQuery( /* your code */ )
const getMore = () => {
if(hasNextPage)
fetchNextPage();
};

Integrating class based Axios request to the hook based code

How can I integrate this class based Axios request to the other hook based code that gets data from a Json file? Basically I want to replace data source LOCATIONS with the Axios get request. Thanks.
componentDidMount () {
axios.get('http://192.168.2.94:3000/list-places').then(res => {
this.setState({
posts: res.data
})
})
}
import { LOCATIONS } from '../data/data'
const HomeScreen = props => {
const renderGridItem = itemData => {
return (
<CategoryGridTile
image={itemData.item.image}
title={itemData.item.title}
onSelect={() => {
props.navigation.navigate({
routeName: 'Categories',
params: {
locationId: itemData.item.id
}
})
}}
/>
)
}
return (
<FlatList
keyExtractor={(item, index) => item.id}
data={LOCATIONS}
renderItem={renderGridItem}
/>
)
}
You just want to get LOCATIONS data from the API? Something like this should work (code is untested)
const HomeScreen = props => {
const [locations, setLocations] = useState(undefined);
useEffect(() => {
async function getLocations() {
const { data } = await axios.get('http://192.168.2.94:3000/list-places');
setLocations(data);
}
getLocations();
}, []);
// ...
return (
<>
{locations && (
<FlatList
keyExtractor={(item, index) => item.id}
data={locations}
renderItem={renderGridItem}
/>
)}
</>
);
};

Resources