Display nested JSON using Flatlist React Native not showing data - javascript

I am making one screen where I am getting data from a fetch API call. In the console its showing the message success and giving the data. Below is the JSON I am getting from API response
{
"msg": "Success",
"type": "success",
"data": {
"15": {
"order_number": "",
"products_info": [
{
"name": "Rose",
"qty": 1,
"base_price": 75
}
],
"can_dispatch": false,
"can_complete": false,
},
"16": {
"order_number": "",
"products_info": [
{
"name": "Rosehip",
"qty": 1,
"base_price": 205
}
],
"can_dispatch": false,
"can_complete": false,
},
"17": {
"order_number": "",
"products_info": [
{
"name": "Cloth Bag ",
"qty": 4,
"base_price": 20
},
],
"can_dispatch": false,
"can_complete": false,
}
},
"success": true
}
I want to display using FlatList. I am getting a response from API and storing in this.state.items
Here is my code
<View style={styles.container}>
<FlatList
data={this.state.items.data}
renderItem={({item}) =>
<View style={{height: 50}}>
<Text style={{height: 50}}>{item.products_info.name}</Text>
<View style={{height: 1,backgroundColor:'gray'}}></View>
</View>
}
/>
</View>
Please help

As per Flatlist docs for React Native, the "data" prop must be an array.
https://reactnative.dev/docs/flatlist#required-data
I've modified your code to get it working - https://snack.expo.io/YkdUl2G4B
Please take a look and let me know if you have any questions or concerns around it.

Related

Looping through array, fetching tweets and returning new reversed array javascript react

UPDATE: I have deployed the site for more context you can view it here https://conundrum-quest-rw-rebuild-web.onrender.com/
the public repo is here
https://github.com/wispyco/conundrum-quest-rw-rebuild
Note: the data on the live site is different but the initial load is loading the hero's on the wrong cards, you can compare the quest with subsequent heros on the home page and the returned data from my function below, you can scroll down to see the rendered cards.
You can see that if you click on a card it shows the correct heros on the single page.
I have the following quests data structure that I am looping through in a separate function and running a fetch to request some profile images from twitter.
[
{
"__typename": "Quest",
"id": 5,
"name": "How do we solve mental health related issues?",
"userId": 17,
"heros": [
{
"__typename": "Hero",
"name": "Anders Kitson",
"twitter": "anderskitson"
},
{
"__typename": "Hero",
"name": "ders",
"twitter": "derz_O"
}
]
},
{
"__typename": "Quest",
"id": 6,
"name": "How do we create a world where North Korea participates and collaborates with the rest of the World?",
"userId": 17,
"heros": [
{
"__typename": "Hero",
"name": "Crypto Dude",
"twitter": "phunk2243"
}
]
}
]
Here is my custom hook
const twitter = useFetchTwitterMultipleQuests(quests)
export const useFetchTwitterMultipleQuests = (twitterProfileManyQuests) => {
const [twitter, setTwitter] = useState([])
useEffect(() => {
twitterProfileManyQuests.forEach(async (twitterProfileMany, i) => {
const woop = twitterProfileMany.heros.map(async (twitterProfile) => {
const test = fetch(
`${window.location.origin}/.redwood/functions/twitter`,
{
method: 'POST',
body: JSON.stringify({ twitter: twitterProfile.twitter }),
}
)
.then(function (response) {
// The response is a Response instance.
// You parse the data into a useable format using `.json()`
console.log('test')
return response.json()
})
.then(function (data) {
return data.data.resultAwaited.data
})
const go = await test
return go
})
const june = await Promise.all(woop)
setTwitter((prevState) => {
return [...prevState, june]
})
})
}, [twitterProfileManyQuests])
const reversedTwitter = twitter.reverse()
return reversedTwitter
}
The problem is the reversedTwitter or twitter variable in the end sometimes is in the correct reversed order and sometimes not reversed, and I can't figure out why.
This is the correct order result
[
[
{
"username": "anderskitson",
"profile_image_url": "https://pbs.twimg.com/profile_images/1428160652237889539/I7ZiM_g8_normal.jpg",
"name": "▲nders on a quest 🜸 to see myself 🪞",
"id": "4633808432"
},
{
"profile_image_url": "https://pbs.twimg.com/profile_images/1496985668043436033/NoyLrUys_normal.jpg",
"name": "ders.eth",
"id": "1389695824934834181",
"username": "derz_O"
}
],
[
{
"username": "phunk2243",
"profile_image_url": "https://pbs.twimg.com/profile_images/1536485988767350784/cfP_sPSC_normal.jpg",
"name": "9999999333 (🅱️uilding 35 Phunks) 🔜",
"id": "1355005208259133442"
}
]
]
This is the incorrect order result
[
[
{
"name": "9999999333 (🅱️uilding 35 Phunks) 🔜",
"profile_image_url": "https://pbs.twimg.com/profile_images/1536485988767350784/cfP_sPSC_normal.jpg",
"username": "phunk2243",
"id": "1355005208259133442"
}
],
[
{
"username": "anderskitson",
"profile_image_url": "https://pbs.twimg.com/profile_images/1428160652237889539/I7ZiM_g8_normal.jpg",
"name": "▲nders on a quest 🜸 to see myself 🪞",
"id": "4633808432"
},
{
"username": "derz_O",
"profile_image_url": "https://pbs.twimg.com/profile_images/1496985668043436033/NoyLrUys_normal.jpg",
"name": "ders.eth",
"id": "1389695824934834181"
}
]
]
The reason this matters is how I am rendering the data. I am rendering a Quest from the quests data, then mapping over the heros in a quest which correspond to the twitter profiles.
See Here
{quests.map((quest, i) => (
<QuestCard key={quest.id}>
<Link to={routes.quest({ id: quest.id })} key={quest.id}>
<div>
<h3>{truncate(quest.name)}</h3>
{quest.heros.map((hero, index) => (
<React.Fragment key={hero.id}>
{twitter.length > 0 && twitter[i] && (
<span>
{hero.name}
<p>{twitter[i][index]?.name}</p>
<img
key={i}
src={twitter[i][index]?.profile_image_url}
alt={twitter[i][index]?.name}
/>
</span>
)}
</React.Fragment>
))}
</div>
</Link>
<div className="clear" />
</QuestCard>
))}
Any help would be greatly appreciated, most of what I have done works, but after about three refreshes the ordering breaks. Thanks
Fixed by using a custom service and a custom sdl in redwood instead of using a function and having to create a custom hook for rendering. This was recommended by the RW team from this article
https://redwoodjs.com/docs/how-to/using-a-third-party-api
And you can see my changes here
https://github.com/wispyco/conundrum-quest-rw-rebuild/pull/8/commits/41637813dd50be70e2e89372606c08e39618fa07

React-Native: Unhandled promise rejection: Error: Objects are not valid as a React child

I have an array of objects that look like the object below and I am trying to render a list. I have other screens that render lists of the same shape in the same manner. I cannot figure out why I am getting an error with this array. The promise is handled correctly and the data is set to the state. The data that I am trying to render is an array.
The error
[Unhandled promise rejection: Error: Objects are not valid as a React child (found: object with keys {external_urls, href, id, name, type, uri}). If you meant to render a collection of children, use an array instead.]
The array: this.state.playlist.items
Array [
Object {
"added_at": "2020-12-06T06:43:39Z",
"added_by": Object {
"external_urls": Object {
"spotify": "https://open.spotify.com/user/",
},
"href": "https://api.spotify.com/v1/users/",
"id": "",
"type": "user",
"uri": "spotify:user:"",
},
"is_local": false,
"primary_color": null,
"track": Object {
"album": Object {
"album_type": "single",
"artists": Array [
Object {
"external_urls": Object {
"spotify": "https://open.spotify.com/artist/4iMO20EPodreIaEl8qW66y",
},
"href": "https://api.spotify.com/v1/artists/4iMO20EPodreIaEl8qW66y",
"id": "4iMO20EPodreIaEl8qW66y",
"name": "Still Woozy",
"type": "artist",
"uri": "spotify:artist:4iMO20EPodreIaEl8qW66y",
},
],
"external_urls": Object {
"spotify": "https://open.spotify.com/album/5mlgzPatuoMGqqHsPIofKr",
},
"href": "https://api.spotify.com/v1/albums/5mlgzPatuoMGqqHsPIofKr",
"id": "5mlgzPatuoMGqqHsPIofKr",
"images": Array [
Object {
"height": 640,
"url": "https://i.scdn.co/image/ab67616d0000b2738d23ae740afca14480db70c8",
"width": 640,
},
Object {
"height": 300,
"url": "https://i.scdn.co/image/ab67616d00001e028d23ae740afca14480db70c8",
"width": 300,
},
Object {
"height": 64,
"url": "https://i.scdn.co/image/ab67616d000048518d23ae740afca14480db70c8",
"width": 64,
},
],
"name": "Wolfcat",
"release_date": "2017-08-31",
"release_date_precision": "day",
"total_tracks": 1,
"type": "album",
"uri": "spotify:album:5mlgzPatuoMGqqHsPIofKr",
},
"artists": Array [
Object {
"external_urls": Object {
"spotify": "https://open.spotify.com/artist/4iMO20EPodreIaEl8qW66y",
},
"href": "https://api.spotify.com/v1/artists/4iMO20EPodreIaEl8qW66y",
"id": "4iMO20EPodreIaEl8qW66y",
"name": "Still Woozy",
"type": "artist",
"uri": "spotify:artist:4iMO20EPodreIaEl8qW66y",
},
],
"disc_number": 1,
"duration_ms": 174221,
"episode": false,
"explicit": true,
"external_ids": Object {
"isrc": "QZ9JZ1701572",
},
"external_urls": Object {
"spotify": "https://open.spotify.com/track/1Hu2OypX8tMPwBcCUaAeO4",
},
"href": "https://api.spotify.com/v1/tracks/1Hu2OypX8tMPwBcCUaAeO4",
"id": "1Hu2OypX8tMPwBcCUaAeO4",
"is_local": false,
"name": "Wolfcat",
"popularity": 63,
"preview_url": "https://p.scdn.co/mp3-preview/b6ac80e632d0c15e097d43083a738bf69ac8bc12?cid=5673f7c36ce34a669e8805ca91f3b103",
"track": true,
"track_number": 1,
"type": "track",
"uri": "spotify:track:1Hu2OypX8tMPwBcCUaAeO4",
},
"video_thumbnail": Object {
"url": null,
},
},
Rendering the list
<View style={{marginBottom: 310}}>
<FlatList
data = {this.state.playlist.items}
renderItem = {({ item }) => (
<ListItem bottomDivider >
<Avatar size={80} source={{uri: item.track.album.images[0].url}} />
<ListItem.Content>
<ListItem.Title>{item.track.name}</ListItem.Title>
<ListItem.Subtitle>{item.track.album.artists[0]}</ListItem.Subtitle>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
)}
keyExtractor={item => item.track.id}
/>
</View>
The error message is actually quite explanatory. If you change your code in following way, for instance:
<ListItem.Subtitle>{item.track.album.artists[0].name}</ListItem.Subtitle>
it should work. React does not allow to use an Object as a child (item.track.album.artists[0] is Object). Only primitive types are allowed (typically String or Number). item.track.album.artists[0].name is String.

Rendering different child components based on data recieved , in a specific order

I am currently using wagtail v2 API to generate a dynamic page content for my react front end. The data comes like this :
"content": [
{
"type": "grid",
"value": {
"grid": [
{
"title": "Fast and reliable",
"subtitle": "Hello there testing this out man",
"button_page": 3,
"image": 2
}
]
},
"id": "e5e370e2-aef0-4ef8-b34f-c4bf9db16e22"
} ,
{
"type": "not-grid",
"value": {
"grid": [
{
"title": "Fast and reliable",
"subtitle": "Hello there testing that out man",
"button_page": 3,
"image": 2
}
]
},
"id": "e5e370e2-aef0-4ef8-b34f-c4bf9db16e12"
}
]
What i wish to do is to render different component onto my parent page in which order matters .
So lets say 'grid' maps to the component <Grid/> and 'not-grid' maps to <NotGrid/> , then the end result of my parent page should look something like this :
<Fragment>
<Grid/>
<NotGrid/>
</Fragment>
Im not sure on how i should attempt to tackle the problem has anybody attempted to do something similar before?
I feel like there should be a function that helps me to map the correct 'type' to the associated 'component' , however im not sure how to implement this in code
You may simply .map() it passing in component conditionally:
const { render } = ReactDOM,
rootNode = document.getElementById('root')
const Grid = () => <div>I'm grid</div>
const NoGrid = () => <div>I ain't no grid</div>
const data = [{type: 'grid'}, {type: 'no-grid'}]
const App = () => {
return (
data.map(({type}) => type == 'grid' ? <Grid /> : type == 'no-grid' ? <NoGrid /> : null)
)
}
render (
<App />,
rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
You can group the type and pass it to component.
let content = [
{
"type": "grid",
"value": {
"grid": [
{
"title": "Fast and reliable",
"subtitle": "Hello there testing this out man",
"button_page": 3,
"image": 2
}
]
},
"id": "e5e370e2-aef0-4ef8-b34f-c4bf9db16e22"
},
{
"type": "not-grid",
"value": {
"grid": [
{
"title": "Fast and reliable",
"subtitle": "Hello there testing that out man",
"button_page": 3,
"image": 2
}
]
},
"id": "e5e370e2-aef0-4ef8-b34f-c4bf9db16e12"
}
]
let grid = content.filter(c => c.type === "grid");
let notGrid = content.filter(c => c.type === "not-grid");
<Fragment>
< Grid grid = {grid}>
< NotGrid notGrid = {notGrid}>
</Fragment>

How can I get all results in ReactiveList

I've tried to use on all data but it doesn't work since I can get only the number of results as stated in the 'size' parameter. Here part of my code.
<ReactiveList
componentId="results"
dataField="original_title"
size={1}
showResultStats={true}
pagination={true}
react={{
and: "searchbox"
}}
onAllData={this.onAllData}
/>
onAllData(shops) {
let result = null;
if (shops !== null) {
console.log(shops.length);
result = shops.map((marker) => (
<ListItem>
<Thumbnail square size={80} source={{ uri: 'https://dummyimage.com/80x80/000/fff' }} />
<Body>
<Text>{marker.name}</Text>
<Text note>{marker.dis}</Text>
</Body>
</ListItem>
))
return result;
}
}
There are a couple of ways you can go about this problem:
Rendering all results with infinite loading
onAllData will give the number of results specified in the size prop. Usually, its not a good idea to set a very high size since it will take more time fetching and rendering the results. A good alternative for this is to use infinite scrolling by setting the pagination prop to false and setting a value in size prop which tells the component how many results to fetch when you reach the end of the list.
Fetching all results using scroll API
tl;dr Demo
Note
This answer uses reactivesearch for web (for demonstration) but you can use the same props in reactivesearch-native since the API is same.
The above approach works fine if you're only interested in rendering the results. But if you wish to fetch all the results for the current query, you can use the scroll API from Elasticsearch. You can use ReactiveList to get the current query and then use it together with the scroll API.
For this purpose, you can make use of the onQueryChange prop on ReactiveList:
First specify an onQueryChange prop on the ReactiveList which receives the previous and current query as parameters:
onQueryChange={(prev, next) => ...}
This function will be invoked each time the query is changed so you can write a logic to fetch the hits for the current query (received in the next parameter) whenever required.
A scroll API call returns the results in the following format:
{
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoAgAAAAClGlY4FlotbmJJZXA0U09lMlZFMUNyQ3M2M0EAAAAApRpWORZaLW5iSWVwNFNPZTJWRTFDckNzNjNB",
"took": 0,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 9407,
"max_score": 1,
"hits": [
{
"_index": "good-books-ds",
"_type": "good-books-ds",
"_id": "5676",
"_score": 1,
"_source": {
"authors": "Arthur C. Clarke, Gentry Lee",
"average_rating": 3.76,
"average_rating_rounded": 4,
"books_count": 48,
"id": 5676,
"image": "https://images.gr-assets.com/books/1375814957l/112518.jpg",
"image_medium": "https://images.gr-assets.com/books/1375814957m/112518.jpg",
"isbn": "1857230213",
"language_code": "eng",
"original_publication_year": 1991,
"original_series": "Rama",
"original_title": "The Garden of Rama (Rama, #3)",
"ratings_count": 16389,
"title": "The Garden of Rama (Rama, #3)"
}
},
{
"_index": "good-books-ds",
"_type": "good-books-ds",
"_id": "5681",
"_score": 1,
"_source": {
"authors": "Darren Shan",
"average_rating": 4.22,
"average_rating_rounded": 4,
"books_count": 52,
"id": 5681,
"image": "https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png",
"image_medium": "https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png",
"isbn": "",
"language_code": "",
"original_publication_year": 2003,
"original_series": "Cirque Du Freak",
"original_title": "Killers of the Dawn (Cirque Du Freak, #9)",
"ratings_count": 18194,
"title": "Killers of the Dawn (Cirque Du Freak, #9)"
}
},
{
"_index": "good-books-ds",
"_type": "good-books-ds",
"_id": "5683",
"_score": 1,
"_source": {
"authors": "Laura Joffe Numeroff, Felicia Bond",
"average_rating": 4.16,
"average_rating_rounded": 4,
"books_count": 13,
"id": 5683,
"image": "https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png",
"image_medium": "https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png",
"isbn": "60278684",
"language_code": "",
"original_publication_year": 2000,
"original_series": "",
"original_title": "If You Take a Mouse to the Movies",
"ratings_count": 17938,
"title": "If You Take a Mouse to the Movies"
}
},
{
"_index": "good-books-ds",
"_type": "good-books-ds",
"_id": "5685",
"_score": 1,
"_source": {
"authors": "Orson Scott Card, James Cameron",
"average_rating": 4.06,
"average_rating_rounded": 4,
"books_count": 15,
"id": 5685,
"image": "https://images.gr-assets.com/books/1225165505l/40289.jpg",
"image_medium": "https://images.gr-assets.com/books/1225165505m/40289.jpg",
"isbn": "99690608",
"language_code": "eng",
"original_publication_year": 1989,
"original_series": "",
"original_title": "The Abyss",
"ratings_count": 16318,
"title": "The Abyss"
}
},
{
"_index": "good-books-ds",
"_type": "good-books-ds",
"_id": "5687",
"_score": 1,
"_source": {
"authors": "Katarina Bivald, Alice Menzies",
"average_rating": 3.56,
"average_rating_rounded": 4,
"books_count": 63,
"id": 5687,
"image": "https://images.gr-assets.com/books/1452107441l/25573977.jpg",
"image_medium": "https://images.gr-assets.com/books/1452107441m/25573977.jpg",
"isbn": "149262344X",
"language_code": "eng",
"original_publication_year": 2013,
"original_series": "",
"original_title": "Läsarna i Broken Wheel rekommenderar",
"ratings_count": 14571,
"title": "The Readers of Broken Wheel Recommend"
}
}
]
}
}
The value received as _scroll_id can be passed to the scroll API to fetch the next set of results and so on till the number of hits is zero.
Note
If your cluster has a lot of data, its not a good idea to run this logic to fetch all the results every time the query changes. You can add a condition to limit the number of results fetched or store the current query in state and only fetch all the results when required.
Here's an example on how you can implement this with ReactiveList. In the example I'm fetching the results each time the query changes but you can modify it to fetch results conditionally instead:
In your render function:
<ReactiveList
...
size={10}
onQueryChange={this.handleQueryChange}
/>
Here's how the handleQueryChange function can look like. This will give you all the results for the current query:
handleQueryChange = async (prev, next) => {
// avoid fetching the results for match_all query since dataset is large
if (next && !next.query.match_all) {
console.log('Fetching all results for query:', next);
// modify the query size here if needed (currently it is 10)
// initial url to obtain scroll id is different
const initialResults = await this.fetchResults(next, url);
// keep scrolling till hits are present
// NOTE: careful if you've a lot of results,
// in that case you might want to add a condition to limit calls to scroll API
const scrollResults = await this.fetchScrollResults({
scroll: "1m",
scroll_id: initialResults._scroll_id
});
// combine the two to get all results
// concat hits from initialResults with hits from scrollResults
const allResults = initialResults.hits.hits.concat(scrollResults);
console.log(`${allResults.length} results found:`, allResults);
}
};
Its using two functions for fetching the results initially and later with the scroll_id. The endpoints for both are different, which you can find in the demo. Here's how the first fetchResults looks like:
fetchResults = (query, api) => {
return fetch(api, {
method: "POST",
headers: {
"content-type": "application/json",
Authorization: `Basic ${btoa(credentials)}`
},
body: JSON.stringify(query)
})
.then(res => res.json())
.catch(err => console.error(err));
};
The fetchScrollResults will use the scroll API to fetch results till the hits obtained are 0.
fetchScrollResults = async query => {
const res = await this.fetchResults(query, scrollUrl);
const { hits } = res.hits;
if (hits.length) {
return [
...hits,
...(await this.fetchScrollResults({
scroll: "1m",
scroll_id: res._scroll_id
}))
];
}
return [];
};
Check the demo, results will appear in the console.
You are missing a key that identify unique components and you also need to wrap element inside function. If function is called properly and your array have elements this should work.
onAllData(shops) {
let result = null;
if (shops !== null) {
console.log(shops.length);
result = shops.map((marker,index) => { return (
<ListItem key={index}>
<Thumbnail square size={80} source={{ uri: 'https://dummyimage.com/80x80/000/fff' }} />
<Body>
<Text>{marker.name}</Text>
<Text note>{marker.dis}</Text>
</Body>
</ListItem>
)})
return result;
}

How to render nested JSON inside JSX in react native?

I want to list the json response. How do i render nested json inside my jsx?
following is json response
[{
"data": {
"total_students": 13,
"seats": "",
"categories": [{
"id": 28,
"name": "Economy",
"slug": "economy",
}],
"instructor": {
"id": "24",
"name": "Ad",
"sub": ""
},
"menu_order": 0
},
"headers": [],
"status": 200
}
This is how the response looks like. Also rendering in react is as shown below
return this.state.user.map(user =>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Text key= {user.data.name} style={styles.userStyle}>{this.state.user.data}</Text>
</View>
</CardSection>
I have tried like the above but getting error in rendering part cannot define name of undefined.What wrong am i doing?please help
You don't have a key name in data object that undefined If you want to nested JSON you can access like
name in instructor : user.data.instructor.name
name in categories (array) : user.data.categories.map(category => category.name)
user.data.name does not seem to be present in your JSON response. The name could be user.data.instructor.name.

Categories