React native : Iterate on a JSON object without getting undefined function - javascript

I'm new to React-Native and I'm learning this by tutorials and examples all over the web. I am trying to do something very simple but it has been a week since I hit this problem and after digging StackOverflow and many other contents, none of them could help. So I decided to ask it directy. My apologies if the question looks duplicate or it seems silly.
I am trying to iterate over a JSON object and display it. All I want to do right now is to show each JSON object with its title (username). I'm planning to do much more - make the title a button and show the details of user after hitting button - but right now this is the big rock I've hit into.
Here is my code. Please note my comment on fetchdata method :
import React, { Component } from 'react'
import { View, Text, FlatList, TouchableOpacity, ListView } from 'react-native'
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.id);
};
render() {
const textColor = this.props.selected ? "red" : "black";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text style={{ color: textColor }}>
{this.props.title}
</Text>
</View>
</TouchableOpacity>
);
}
}
export default class HttpExample extends Component {
constructor(props) {
super(props);
this.state = {
data: '',
username: [],
first_name: '',
last_name: ''
};
//Using ES6 we need to bind methods to access 'this'
this.fetchData = this.fetchData.bind(this);
}
componentDidMount() {
this.fetchData();
}
fetchData() {
// The first line - which is commented - returns all of non-admin
// users, the second one returns only one user. Note that the
// second one works fine and the first one does not.
// fetch('http://URL/users.json', {
fetch('http://URL/users/12345678001.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
data: responseJson,
username: responseJson.username,
first_name: responseJson.first_name,
last_name: responseJson.last_name
})
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
_onPressItem = (id: string) => {
// updater functions are preferred for transactional updates
this.setState((state) => {
// copy the map rather than modifying state.
const selected = new Map(state.selected);
selected.set(id, !selected.get(id)); // toggle
return {selected};
});
};
_renderItem = ({item}) => (
<MyListItem
id={item}
onPressItem={this._onPressItem}
title={this.state.username}
/>
);
render() {
return (
<FlatList
data={[this.state.data]}
renderItem={this._renderItem}
/>
)
}
}
And here is a sample of one of my JSON objects created by Django ReST framework, written by myself. I've just simplified the object a bit and removed some of the fields, for better reading (The avatar field is a base64 image field and it is much smaller than the original one):
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}
The above is what I get by calling http://URL/users/12345678001.json which returns one user. I have been able to show the user as one touchable opacity in the application (the above code works) But when I call users.json which has a structure like below:
[{user1 data},{user2 data}, etc.]
I cannot make the mobile application display each user's username in the mobile output. Either I get nothing (nothing is displayed) or the usual errors pop up (TypeError: object is not a function, etc.) I want to have the application iterate through the whole users.json and show each user's username as one touchable opacity. I've tried using .map which throws me the error, or calling each object in responseJson by their array index which either shows me nothing or throws error.
Let me know about your ideas and solutions.
FYI, I am testing this on my Nexus 5X phone directly.
Update
Here is an example of users.json as it reflects in my console log :
[{
"username": "12345678001",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678000",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-03-28",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
},
{
"username": "12345678003",
"email" : "sample#gmail.com",
"first_name": "AAA",
"last_name": "BBB",
"phone_number": "12045678003",
"gender": "M",
"city": "NY",
"description": "",
"date_of_birth": "2010-12-20",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAPBhAREQ8QDQ8PDxIWEBAWFRANDxAQFRUWFhURExUYHSggGBolGxUTITEhJSkrLi4uFx8zODMsNygtLisBCgoKBQUFDgUFDisZExkrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrK//AABEIAOEA4QMBIgACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABAUBAgMGB//EADIQAQABAwEHAQYEBwAAAAAAAAABAgMRBAUSITFBUXFhIjKRobHBM4HR8RMjQmJyguH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/APpgCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIAAAAAAAAAAAAAAAAAAAAAAANrduaq8RGZkGqVY0FdXON2PXn8E/SaOKIzPGrv0jwlAhW9nURHHNU/B3p0tER7sOwDjVpaJj3YcbmzqJjhmJTAFPf0FdPGPaj5/BEejRtV",
"groups": [1,2],
"user_permissions": [],
"interests": [1,2]
}]
Another Update
As requested, here is a screenshot of my console, note that it differs from what I've posted here and has many different fields :
More Investigation:
I decided to make the code much simpler, and just focus on the main problem. How to return the iterated object for display:
My code is now this:
import React, { Component } from 'react'
import { View, Text, ListView } from 'react-native'
export default class HttpExample extends Component {
constructor(props) {
super(props);
data = [''];
}
fetchData() {
fetch('http://URL/users.json', {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
console.log("ResponseJson is :" + responseJson);
console.log(responseJson.users.length);
console.log(responseJson.users.username);
console.log(responseJson.users);
console.log("THIS:::" + responseJson.users[0].username);
responseJson.users.map((user) =>
{
console.log("THIS:::" + user.username);
data.push(user.username);
console.log("This.data:" + data[0] + "second:" + data[1]);
});
return data;
})
.catch((error) => {
console.error(error);
});
}
_keyExtractor = (item, index) => item.id;
render() {
return (
<View>
<ListView
dataSource={this.fetchData()}
renderRow={(data) => <Text>{data.username}</Text>}
/>
</View>
)
}
}
All of the "console.log" commands return with correct info (Check the end of the post), but my render does not work and throws undefined is not a object. I really don't understand what is the exact problem? isn't data an array? Why it can't be displayed and throws TypeError? What am I getting wrong?
console.log outputs, in correct order :
ResponseJson is :[object Object]
3
undefined
(whole users.json is returned)
THIS:::12345678001
THIS:::12345678001
This.data:second:12345678001
THIS:::12345678002
This.data:second:12345678001
THIS:::12345678003
This.data:second:12345678001

Related

How to send array of objects in props to a custom component in React Native?

I have an array when I fetch from the API by using axios get request as follows:
useEffect(async () => {
console.log("here");
let accessToken = await AsyncStorage.getItem("accessToken");
const response = await axios
.get(API_URL + "/feed", {
headers: {
Authorization: "Bearer " + accessToken,
},
})
.then((response) => {
setFeedItems([]);
setFeedItems((feedItems) => [...feedItems, ...response.data]);
setIsLoading(false);
});
}, []);
I have a custom component which is Report.js and I want to send some information from this screen to that component by using the following code:
{isLoading == false && (
<FlatList
style={{ marginLeft: 10, marginRight: 10 }}
data={feedItems}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Report
name="mustafa"
username="mustafa123"
responsibleInstitution="responsible"
userId={item.userId}
category={item.category}
location={item.location}
institutionId={item.institutionId}
description={item.description}
upvotes={item.upvotes}
comments={item.comments}
/>
)}
></FlatList>
The shape of the data that is coming from the API is as follows:
[
{
"id": "6228a72cfc2ce87bb0b5f908",
"userId": "61cab704ee5f9a5cc3bd844c",
"institutionId": "61cabb2da10a9147a53e6480",
"solutionId": null,
"description": "Kayıp ilanı..",
"category": "Missing",
"comments": [
{
"id": "6228c0933ab2f166af0a9d23",
"userId": "61cab704ee5f9a5cc3bd844c",
"text": "Tamam kardeş anladık",
"date": "2022-03-09T14:58:27.091+00:00"
},
{
"id": "6228c98534572422056eb565",
"userId": "61cab704ee5f9a5cc3bd844c",
"text": "Tamam kardeş anladık 3",
"date": "2022-03-09T15:36:37.256+00:00"
}
],
"upvotes": [
"61cab704ee5f9a5cc3bd844c"
],
"location": null,
"report_image_link": null,
"file": null,
"date": "2022-03-09T13:10:04.273+00:00"
},
As you can see from the data, the 'comments' field has an array of objects with id, userId, text, and date fields. Whenever I run the code, I get the following error which is caused by the comments={item.comments} line.
The error: Objects are not valid as a React child (found: object with keys {id, userId, text, date}). If you meant to render a collection of children, use an array instead.
What I want to do is that, whenever user click a button in the Report.js component, I want to open up a modal and present the comments to the user on that component. Do you think I should change my way? How can I send the comments information to the Report component? If my approach is incorrect, what should I do?
Since comments is an array of objects, you cannot pass it as a child to a Text component. Now, it depends on how you want to visualize your data. Here is a possible solution using FlatList. You could replace the rendered component with whatever suits you the best.
const dummyData = [
{
"id": "6228c0933ab2f166af0a9d23",
"userId": "61cab704ee5f9a5cc3bd844c",
"text": "Tamam kardeş anladık",
"date": "2022-03-09T14:58:27.091+00:00"
},
{
"id": "6228c98534572422056eb565",
"userId": "61cab704ee5f9a5cc3bd844c",
"text": "Tamam kardeş anladık 3",
"date": "2022-03-09T15:36:37.256+00:00"
}
]
const App = () => {
const [data, setData] = useState(dummyData);
return (
<SafeAreaView style={{ flex: 1 }}>
<View>
<FlatList
data={data}
renderItem={({item}) => {
return <Text style={{margin: 20}}>`ID: ${item.id} userId: ${item.userId} text: ${item.text} date: ${item.date}`</Text>
}}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</SafeAreaView>
);
};

Recursively mapped nested JSON but components do not render

I recursively mapped nested JSON, and console log output all elements in format: property => value correctly, but components do not render. Following is JSON:
{
"index": "dwarf",
"name": "Dwarf",
"speed": 25,
"ability_bonuses": [
{
"ability_score": {
"index": "con",
"name": "CON",
"url": "/api/ability-scores/con"
},
"bonus": 2
}
],
"alignment": "Most dwarves are lawful, believing firmly in the benefits of a well-ordered society. They tend toward good as well, with a strong sense of fair play and a belief that everyone deserves to share in the benefits of a just order.",
"age": "Dwarves mature at the same rate as humans, but they're considered young until they reach the age of 50. On average, they live about 350 years.",
"size": "Medium",
"size_description": "Dwarves stand between 4 and 5 feet tall and average about 150 pounds. Your size is Medium.",
"starting_proficiencies": [
{
"index": "battleaxes",
"name": "Battleaxes",
"url": "/api/proficiencies/battleaxes"
},
{
"index": "handaxes",
"name": "Handaxes",
"url": "/api/proficiencies/handaxes"
},
{
"index": "light-hammers",
"name": "Light hammers",
"url": "/api/proficiencies/light-hammers"
},
{
"index": "warhammers",
"name": "Warhammers",
"url": "/api/proficiencies/warhammers"
}
],
"starting_proficiency_options": {
"choose": 1,
"type": "proficiencies",
"from": [
{
"index": "smiths-tools",
"name": "Smith's tools",
"url": "/api/proficiencies/smiths-tools"
},
{
"index": "brewers-supplies",
"name": "Brewer's supplies",
"url": "/api/proficiencies/brewers-supplies"
},
{
"index": "masons-tools",
"name": "Mason's tools",
"url": "/api/proficiencies/masons-tools"
}
]
},
"languages": [
{
"index": "common",
"name": "Common",
"url": "/api/languages/common"
},
{
"index": "dwarvish",
"name": "Dwarvish",
"url": "/api/languages/dwarvish"
}
],
"language_desc": "You can speak, read, and write Common and Dwarvish. Dwarvish is full of hard consonants and guttural sounds, and those characteristics spill over into whatever other language a dwarf might speak.",
"traits": [
{
"index": "darkvision",
"name": "Darkvision",
"url": "/api/traits/darkvision"
},
{
"index": "dwarven-resilience",
"name": "Dwarven Resilience",
"url": "/api/traits/dwarven-resilience"
},
{
"index": "stonecunning",
"name": "Stonecunning",
"url": "/api/traits/stonecunning"
},
{
"index": "dwarven-combat-training",
"name": "Dwarven Combat Training",
"url": "/api/traits/dwarven-combat-training"
},
{
"index": "tool-proficiency",
"name": "Tool Proficiency",
"url": "/api/traits/tool-proficiency"
}
],
"subraces": [
{
"index": "hill-dwarf",
"name": "Hill Dwarf",
"url": "/api/subraces/hill-dwarf"
}
],
"url": "/api/races/dwarf"
}
Then this is code:
import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'
import TypeComponent from './type_component'
import TestComponent from './test_component'
class raceWindow extends Component {
constructor(props)
{
super(props)
this.state = {
data: {}
}
}
componentDidMount()
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
componentDidUpdate(prevProps)
{
if(this.props.hdAPI !== prevProps.hdAPI)
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
}
isType (attr, value)
{
if(Array.isArray(value))
{
value.map((v) => {
Object.entries(v).map(([a1,v1]) => this.isType(a1,v1))
})
}
else
{
if(typeof value === 'object')
{
Object.entries(value).map(([a,v]) => this.isType(a,v))
}
else
{
console.log(attr);
console.log(value);
return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
}
}
};
render()
{
const { data} = this.state;
//I also tried to do the recursive map in a component, but it does not work either
/*
return(
<div>
<Grid container columns = {10}>
<TypeComponent attr = {""} value = {data} />
</Grid>
</div>
);*/
return(
<div>
<Grid container columns = {10}>
{this.isType("",data)}
</Grid>
</div>
);
}
}
export default raceWindow
When I tried to map it manually in the first layer, only first layer components rendered. Nested data in deeper layers do not render, though console output the deeper data correctly. So I assume react do not render deeper component. How should I deal with this?
Edit: Just note, I may be wrong, but I think every loop of isType() will go to this part of code at last:
else
{
console.log(attr);
console.log(value);
return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
}
console also output all non-array, non-object value in the log, but return() in this block does not render.
First let's look at the main problems you have right now:
The if blocks inside your isType function do not return anything. You are running functions against the value argument, but then you're not doing anything with what those functions return. Fixing this can be as simple as changing value.map... to value = value.map..., but if you don't do something, then when you get to the return at the end, those if blocks will have no impact on the final result.
Inside the first if block, your value.map... function doesn't return anything since you have brackets around Object.entries.... You just need to return Object.entries..., or else remove the brackets.
If we fix those problems and simplify the if/else logic a bit, we end up getting something back in the JSX:
isType(attr, value) {
let returnValue = value;
if (Array.isArray(returnValue)) {
returnValue = value.map((v) => {
return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
});
} else if (typeof returnValue === "object") {
returnValue = Object.entries(value).map(([a, v]) => this.isType(a, v));
}
return (
<Grid.Column>
<Label>{attr}</Label>
{returnValue}
</Grid.Column>
);
}
But you'll see when you get this far that the resulting DOM probably isn't what you want.
Instead, I recommend changing the approach a bit so that we first convert our JSON into a structure we can use and then map over it in our render function. This will hopefully also make it a little easier to reason about what is happening when and to modify your function to only add things to the final output that you actually care about.
That'd look something like this:
class RaceWindow extends Component {
constructor(props) {
super(props);
// your JSON; store in state if necessary
this.data = {};
// create a placeholder variable
this.finalDom = [];
// call `this.isType` to fill in that variable
// the result is a giant array of shape {attr: 'str', value: 'str'}
this.isType("", this.state.data);
}
isType(attr, value) {
if (typeof value === "string") {
this.finalDom.push({
attr,
value
});
}
if (Array.isArray(value)) {
this.finalDom.push({
attr,
value: value.map((v) => {
return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
})
});
}
if (typeof value === "object") {
this.finalDom.push({
attr,
value: Object.entries(value).map(([a, v]) => this.isType(a, v))
});
}
}
render() {
return (
<div>
<div class="container">
{this.finalDom.map((obj) => (
<div class="item">
<div class="label">{obj.attr}</div>
{obj.value}
</div>
))}
</div>
</div>
);
}
}
CodeSandbox demo of the above.
Final note: Make sure you capitalize the first letter of your component, or else React won't recognize it as a component.
Following is working code:
import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'
import TypeComponent from './type_component'
import TestComponent from './test_component'
class raceWindow extends Component {
constructor(props)
{
super(props)
this.state = {
data: {}
}
}
componentDidMount()
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
componentDidUpdate(prevProps)
{
if(this.props.hdAPI !== prevProps.hdAPI)
{
fetch(this.props.hdAPI)
.then(response=>response.json())
.then(data => {this.setState({data: data})});
this.setState({hdAPI: this.props.hdAPI});
}
}
isType (attr, value, obj)
{
if(Array.isArray(value))
{
value.map((v) => {
Object.entries(v).map(([a1,v1]) => this.isType(a1,v1,obj))
})
}
else
{
if(typeof value === 'object')
{
Object.entries(value).map(([a,v]) => this.isType(a,v,obj))
}
else
{
var pair = {}
pair[attr] = value
obj.push(pair);
}
}
};
render()
{
const { data} = this.state;
var obj = [];
return(
<div>
<Grid container columns = {5}>
{this.isType("",data,obj)}
{
obj.map((arr, i) => {
return(
Object.entries(arr).map(([a,v]) => {
return(
<Grid.Column key = {i}><Label key = {i} color = 'orange'>{a}</Label>{v}</Grid.Column>
);
})
);
})
}
</Grid>
</div>
);
}
}
export default raceWindow
Thanks cjl750's advice, I use an variable to collect results from recursive function and it works. I also tried to let very if block has a return as his advice, but components still do not render. Not sure why.
For now, it seems jsx returned from deep layer in recursive function do not render.

react antd upload component is repeating elements when rendering images after GET from server

when the component is rendered for the first time, it gets its content from an api call response and shows that. It should show an array of images(which it does), but it is repeating some of them, the component Upload double shows the first n-1 elements in the array fileListGallery, even when in the component the array fileListGallery does not have repeated values
here is the most significant part of the code involved
const [images, setimages] = useState({
previewVisible: false,
previewImage: "",
previewTitle: "",
fileListGallery: [],
fileListThumbnail: []
})
const product = useSelector(state => state.product);
const { gallery } = product;
this is the state of the component and variables from global state
useEffect(() => {
dispatch(getProductFiles(pid));
},[])
useEffect(() => {
gallery ? setimages(gallery) : null;
}, [gallery])
here I dispatch an action for getting the images from the server and assign the response to the local state, the response from the server is an array of objects(images) which is assigned to fileListGallery
example object(image)
{
"id": 187,
"url": "imageurl",
"urlBig": null,
"urlSmall": null,
"name": "file-20210617012922",
"mime": "image/jpeg",
"uid": "__AUTO__1623937098548_0__"
}
ant.design upload component returned.
const { previewVisible, previewImage, fileListGallery, fileListThumbnail, previewTitle } = images;
return (
<Upload
listType="picture-card"
fileList={fileListGallery}
onPreview={handlePreview}
onChange={(list) =>
handleChange(list, { type: "thumbnail" })
}
action={`server url`}
headers={{ 'Authorization': `Bearer ${tokenHelper.getItem('token')}` }}
onRemove={onRemoveImage}
accept="image/*"
>
fileListGallery.length >= 1 ? null : uploadButton}
</Upload>
)
an example of the repeated images in the Upload component

React js Apollo Destructuring Result

This is my second simple query from the Apollo client. My first attempt queries a list of users and displays them, works just fine. I don't understand what the differences between my two query functions.
So I'm trying to make a super simple query from an Apollo client. The query is two fields the id and client name. The query is executed and results are returned, verified by console.log(data). So I believe the server is work properly and the query is working. I ran the Apollo codegen to download and create the ts files that contain my interfaces.
I also have copied the output from Apollo's Playground and created little plain java script destructure. I was able to destructure the result quiet easily, but I can't apply that code to the React project. Best I can seem to do is display "pt_Clients" nothing else. I have been stuck on this for embarrassing amount time.
clients.tsx
export const GET_CLIENTS = gql`
query pt_Clients {
pt_Clients {
id
clientname
}
}`;
interface ClientsProps extends RouteComponentProps { }
const PTClients: React.FC<ClientsProps> = () => {
const {
data,
loading,
error
} = useQuery<
pt_ClientsTypes.pt_Clients_pt_Client
>(GET_CLIENTS);
if (loading) return <Loading />;
if (error) return <p>ERROR</p>;
if (!data) return <p>Not found</p>;
return (
<Fragment>
<nav>
<ul>
<h3>Client List</h3>
{console.log(data)}
{
data &&
Object.keys(data).map((client: any) => (
<li>
<Link to={'/admin/pt/clients/:' + client.id} >{client.clientname}</Link>
</li>
))
}
</ul>
</nav>
<Switch>
<Route
path='/admin/pt/clients/:id'
render={({match}) => {
const { id } = match.params;
return <AdminClient clientid={id} />
}}
/>
</Switch>
</Fragment>
);
}
export default PTClients;
my codegen file types/pt_Clients.ts
/* tslint:disable */
/* eslint-disable */
// #generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: pt_Clients
// ====================================================
export interface pt_Clients_pt_Client {
__typename: "pt_Client";
id: number,
clientid: number;
status: number | null;
clientname: string | null;
}
export interface pt_Clients {
pt_Client: pt_Clients_pt_Client | null;
}
Playground Results
{
"data": {
"pt_Clients": [
{
"id": 1,
"clientname": "Client A",
"__typename": "pt_Client"
},
{
"id": 2,
"clientname": "Client B",
"__typename": "pt_Client"
},
{
"id": 3,
"clientname": "Client C",
"__typename": "pt_Client"
},
{
"id": 4,
"clientname": "Client D",
"__typename": "pt_Client"
}
]
},
"loading": false,
"networkStatus": 7,
"stale": false
}
Thanks for taking the time to read and any help that offered.
Okay. So first things first.
The clients array is in data.pt_Clients not in data itself. So to render the list of clients, you need to do data.pt_Clients.map((client : any))
Second, the to prop for Link should not contain the : character. It should be there, as you've correctly written inRoute component's path prop only.
Check the following code
<ul>
<h3>Client List</h3>
{console.log(data)}
{
data &&
data.pt_Clients.map((client: any) => (
<li>
<Link to={`/admin/pt/clients/${client.id}`}>
{client.clientname}
</Link>
</li>
))
}
</ul>
On a sidenote, the li, and Link elements should contain akey prop.

(React Native) Retrieving next value in JSON file when button is pressed

Let's say I have a local JSON file (./movies.json) structured as
{ "movies": [
{ "title" : "Terminator", "year" : "1984", "genre" : "Action" },
{ "title" : "Jumanji", "year" : "2017", "genre" : "Adventure"},
 { "title" : "Incredibles 2", "year" : "2017", "genre" : "Animation"}]
}
Whenever a button is clicked, I want to output, for example, a Text Field with
Terminator --> Jumanji --> Incredibles 2, in order.
I also want to be able to access all three of "title", "movie", "genre" (in separate text fields) in order, when the button is clicked.
This is what I have so far, to get just the titles of the movies in order.It doesn't work, because I don't think I'm pulling from the JSON file correctly.
import jsonData from "./movies.json";
export default class Movies extends React.Component {
constructor(props) {
super(props);
this.state = {
results:{
titles: [],
years: [],
genres: []
}
}
};
}
componentDidMount = () => {
// const data = json.stringify(jsonData) I think this line is not correct
this.setState({ data })
}
render () {
titles_list = this.state.results.titles.map((item) => {
return (
<View key={item.title}>
<Text>
{item.title}
</Text>
</View>
);
});
return (
<View>
{titles_list}
</View>
);
}
}
I'm not sure how to implement a button so that when it is pressed, the next title/year/genre is shown. Help would be appreciated. Thanks!
Store the index of the array in a state variable.
First of all, I will assume that you passed that json into state.movies
So initialize it as follows:
this.state = {
movies: [], // where the movies are
displayIndex: 0 // This will be the index that you show
}
When you press your button call a function that will call either of the following functions:
moveForward(){
this.setState({displayIndex: this.state.displayIndex++})
}
moveBack(){
this.setState({displayIndex: this.state.displayIndex--})
}
Then when you display the fields under your render function grab the object you need as follows:
render(){
const movieData = this.state.movies[this.state.displayIndex];
....//Do the display logic here

Categories