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.
Related
I am trying to render the data called items in nextjs and I have been debugging it for a while. below is my code that causes the error. the goal is to render the descriptions in an array as alist and render the description that is a string as it is but i can not use the map function because of the fist description(which is a string). I am also trying to not use dangerouslysetinnerhtml.
export default function SingleCareerContainer(){
const items = [
{
title: "About",
description:
"We are developing new functionality for an application },
{
title: "Requirements",
description: [
"3+ years of working experience.",
"Extensive experience in Swift. ",
"mobile development life cycle.",
"good communication skills.",
],
},
{
title: "Responsibilities",
description: [
"write program code according to the defined application architecture.",
"Implement code refactoring. ",
"refactoring and optimization results. ",
"Develop, document, and edit programming interfaces.",
"Estimating tasks .",
],
},
{
title: "What we Offer",
description: [
"Above average compensation.",
"Close cooperation.",
"Challenging tasks. ",
],
},
];
for (const item of items) {
let rep = item.description;
if(rep.length > 1){
const ree = rep.map((reps, i) => {
return(
<Text key={i}>{reps}</Text>
)
})
}else{
return(ree);
}
const itemcomp = items.map((item, i) => {
return (
<>
<div>
<p>
{item.title}
</p>
</div>
</>
);
});
return (
<>
<Container>
<p>
Frontend Developer
</p>
<Button width={"auto"} height={"60px"}>
Apply
</Button>
<>
<p>
<div>{itemcomp}</div>
{ree}
</p>
</>
</Container>
</>
);
}
`
A string is also an array under the hood so you can't reliably distinguish between an array and a string with .length property. You need to use typeof operator because an array has 'object' value while string has 'string' value if you apply it to both types.
Pseudo-code:
if (typeof description === 'string') {
return description
} else {
return description.map(item => <Text>item</Text>)
}
I use JSON and useStaticQuery to pass data about links on my website. For example—
simBarItems.json
[
{
"content": "Provia",
"url": "/foto/provia",
"id": 1
},
{
"content": "Velvia",
"url": "/foto/velvia",
"id": 2
},
{
"content": "Astia",
"url": "/foto/astia",
"id": 3
},
{
"content": "Classic Chrome",
"url": "/foto/classic-chrome",
"id": 4
},
{
"content": "Acros",
"url": "/foto/acros",
"id": 5
},
{
"content": "PRO Neg.",
"url": "/foto/pro-neg",
"id": 6
}
]
SimBar.jsx
import React from "react"
import { Link, useStaticQuery, graphql } from "gatsby"
import { container } from "./SimBar.module.scss"
function isActive({ isCurrent }) {
return isCurrent ? { className: "active" } : {}
}
function isPartiallyActive({ isPartiallyCurrent }) {
return isPartiallyCurrent ? { className: "active" } : {}
}
export default function SimBar() {
const data = useStaticQuery(graphql`
query {
allSimBarItemsJson {
nodes {
id
content
url
}
}
}
`)
let items = data.allSimBarItemsJson.nodes
return (
<nav className={container}>
<ul>
<li>
<Link to="/foto" getProps={isActive}>
Alle foto
</Link>
</li>
{items.map(item => (
<li key={item.id}>
<Link to={item.url} getProps={isPartiallyActive}>
{item.content}
</Link>
</li>
))}
</ul>
</nav>
)
}
As you can see, most items should have the same stateProp, so they can go in the same map. However, the first item should have a different stateProp.
My question is: How can I pass the stateProp through JSON so that I can include the item with the isActive link in the map? Is it possible?
Thanks!
If you want to modify your JSON data, you have a few options (at least):
Modify directly the JSON to add the isActive attribute only in the first element
Tweak your data directly in the component
Before the loop:
let items = data.allSimBarItemsJson.nodes
items[0].isActive=true
So now your first item has the attribute active so when you loop you can access to it:
{items.map(item => {
console.log("has isActive attribute: ", item.isActive)
return <li key={item.id}>
<Link to={item.url} getProps={isPartiallyActive}>
{item.content}
</Link>
</li>
})}
Using the index to determine which one is the first, hence isActive, on the fly:
{items.map((item, index) => {
console.log("has active attribute: ", index===0)
return <li key={item.id}>
<Link to={item.url} getProps={isPartiallyActive}>
{item.content}
</Link>
</li>
})}
As you can see in the docs, the map loop as a second argument takes the index so you can access to the first position at any time (index===0).
Each implementation will be more optimal depending on what you want to achieve with the isActive (i.e: if it needs to change between items or not).
Here's what I am trying to do. I am getting a bunch of objects back from a JSON response (locally). I want to display the first let's say 12 coming back but want to add a "see more" link to show the next series of 12. I know you can split arrays but in my case, not sure if I should even split them rather just have the "see more" link show the next 12 in the array of objects coming back. I imagine it's creating a function that calls 12 (or whatever number) at a time or something when you click the link. hope that makes sense. Thanks
Release component (looping through JSON to display releases)
import releases from "../data/releases.json";
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import '../main.css'
const Release = () => {
//experimenting with splitting up array but not implemented yet
function sliceIntoChunks(arr, chunkSize) {
const res = [];
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
res.push(chunk);
}
return res;
}
console.log(sliceIntoChunks(releases, 3));
return (
<Wrapper>
<div className="release fadein">
{releases.map((release, i) => (
<div className="item" key={i}>
<Link to={`/release/${release.id}`}>
<img src={release.imageURL} alt={release.artist} />
</Link>
</div>
))}
{/* Implement here to show the next 12 in the array*/}
See more...
</div>
</Wrapper>
)
}
Json file (showing the first 3 objects for brevity but there's say 40 or 50 that will be coming back)
[
{
"id": 0,
"artistID": "ES",
"imageURL": "../images/releases/cloudbursts.jpg",
"title": "Cloud Bursts",
"artist": "ERIC SHANS",
"description": "One of the main 3Bridge Records bosses Eric Shans is back with his first original music of 2022, 'Cloud Bursts'. .",
"buy": "https://www.beatport.com/release/ardour/3096956",
"stream": "https://open.spotify.com/album/5vNYmx4uNY5fIPrOCR0cUa?si=lwCXwLGtSn6g6ZNToPZKRQ"
},
{
"id": 1,
"artistID": "ES",
"imageURL": "../images/releases/archtypes.jpg",
"title": "Archetypes",
"description": "Mexico City based artist Eisenheim is back on 3Bridge with a killer EP called 'Archetypes'.n",
"artist": "ERIC SHANS",
"buy": "https://www.beatport.com/release/we-choose/1916121",
"stream": "https://open.spotify.com/album/4cutoknbgciTGGpAYSZXfK?si=gsNvR6ytTN6KdrPORfSLOg"
},
{
"id": 2,
"artistID": "BG",
"imageURL": "../images/releases/pingpong.jpg",
"title": "Ping Pong",
"artist": "SIMON SAMPLER & FISCHMEHL",
"description": "We welcome Simon Sampler back to the label for a great 2 tracker featuring Austrian producer Fischmehl as well.",
"buy": "https://www.beatport.com/release/cloud-bursts/3687306",
"stream": "https://open.spotify.com/album/4cutoknbgciTGGpAYSZXfK?si=gsNvR6ytTN6KdrPORfSLOg"
}
]
Would recommend having a simple button that add extra 12 items to a state when clicking. It's easily done by using the .slice() array method:
import React from "react";
const STEP = 12;
const data = [...Array(100).keys()].map((id) => ({ id }));
export default function App() {
const [items, setItems] = React.useState(data.slice(0, STEP));
const loadMore = () => {
setItems([...items, ...data.slice(items.length, items.length + STEP)]);
};
return (
<div className="App">
<ul>
{items.map((item) => {
return <li>{item.id}</li>;
})}
</ul>
<button onClick={loadMore}>Load more</button>
</div>
);
}
Use usestate hook to extend
Const [present ,setPresent]=useState(12)
releases.slice(0, present).map(()=>
return div here) )
<a onClick={()=>setPresent (present+12)}
See more
I have user interface which looks should look like this
and that picture above is just pure HTML.
So when I tried to create it with React, I am failing to align the tv shows with a particular TV channel overflowing horizontally as per the channel.
Picture of what I get in React
I am querying the data from json files that have the objects and the TV channel object looks like
{
"groupID": 16481,
"hasMediathek": true,
"storeUrlAndroid": null,
"storeUrlApple": null,
"liveWeb": "https://www.zdf.de/live-tv",
"liveApp": null,
"defaultOrder": 1000,
"hdp": false,
"quality": 2,
"name": "ZDFneo HD",
"isEncrypted": false,
"isHD": false,
"dvbTriplet": "dvb://0.0.0",
"id": null,
"major": true
}
this is connected to the shows through its groupID which shows up as channelID in the shows Object. Below is a sample for the shows object
{
"_id": "5b1f5c7da6cdf0cbbdb7e700",
"showID": 892149863,
"channelID": 16481,
"title": "Masters of Sex",
"subtitle": "Auf frischer Tat ertappt (Dirty Jobs)",
"serie": {
"no": "4",
"title": "Auf frischer Tat ertappt",
"seasonno": "2",
"info": "Staffel 2 | Folge 4"
}
this what I have done to query the data for channels
import stations from "../data/channels.json";
import data1 from "../data/1.json";
import data2 from "../data/2.json";
import data3 from "../data/3.json";
import data4 from "../data/4.json";
import data5 from "../data/5.json";
import data6 from "../data/6.json";
class Contents extends React.Component {
constructor(){
super();
this.trans = this.trans.bind(this);
}
station = { ...stations };
shows = { ...data1, ...data2, ...data3, ...data4, ...data5, ...data6 };
trans(){
Object.values(station.result.channels).map(value => {
console.log(value["groupID"], "odgdggddgdd");
return value["groupID"];
});
}
render() {
return (
<Fragment>
<TopNavBar />
<BottomNavBar />
<div className="row">
<section className="left-menus">
<div className="left-items">
{Object.values(station.result.channels).map(value => (
<div>
<img
src={`https://cdn.hd-plus.de/senderlogos/bright-cropped/${value["groupID"]}.png`}
alt=""
/>
</div>
))}
</div>
</section>
<section className="item-center">
{
Object.values(shows.result).map(value => (
<div className="shows">{
<div className="grid-items">
<div className="item">
<small>{value.startime}</small>
<small>value.resolution</small>
</div>
<div className="item-name">{value.title}</div>
</div>
}
</div>))}
</section>
</div>
</Fragment>
);
}
}
export default Contents;
I need some help with aligning the channels with their respective stations. I hope this is descriptive enough. Thank you
Updated Code for the tiles
<section className="item-center">
{
Object.values(station.result.channels).map(value => (
<div className="shows">{
shows.result.find(show => show['channelID'] === value['groupID']).map(item => (
<div className="grid-items">
<div className="item">
<small>{item.startime}</small>
<small>value.resolution</small>
</div>
<div className="item-name">{item.title}</div>
</div>
))}
</div>))}
</section>
error message
when I try to add Object.values() around it I get this
The correct solution for this (as found in the comments) is to use the filter() function. a find() function would only give back one object, or undefined, so you cannot use map on it.
shows.result.filter(show => show['channelID'] === value['groupID']).map(item =>
())
This will return every object where the channelID equals the groupID, which you can then map to a ui element.
https://www.w3schools.com/jsref/jsref_filter.asp
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