JSON in Gatsby with GraphQL - javascript

I have one JSON file named Test.json with all data in it.
[ { "name" : "Margo",
"birthDate": "1990.03.15",
"timetable": [
{"time": "8.00",
"task": "toDoMargoElem1"},
{"time": "9.00",
"task": "toDoMargoElem2"}
},
{ "name" : "Arthur",
"birthDate": "1990.03.15",
"timetable": [
{"time": "8.00",
"task": "toDoArthurElem1"},
{"time": "9.00",
"task": "toDoArthurElem2"}
}
}
I'd like to use call data from component, so I tried to call GraphiQL. Code exporter gives me
const ComponentName = () => {
const data = useStaticQuery(graphql`
{
allTestJson {
edges {
node {
name
timetable {
time
task
}
}
}
}
}
`)
return <pre>{JSON.stringify(data, null, 4)}</pre>
}
In my component Mycomponent I did next
import React from 'react'
import {useStaticQuery, graphql} from 'gatsby'
export default function Sched() {
const data = useStaticQuery(graphql`
{
allTestJson {
edges {
node {
name
timetable {
time
task
}
}
}
}
}
`)
const results = data.allTestJson.edges.map (({node}) => {
const {name, time, task} = node;
return {
name,
time,
task
}
})
return (<div>
{results.map (({eventName, time, task})=>
<div key = {name}>
{name}
{time}
{task}
</div>
)}
</div>
)
}
But as a result i see just construction like
<div> {name} </div>
<div> {name} </div>
How can I see {time, task}?
Why map doesn't show all nodes of my objects?

Check the object desctructing
const results = data.allTestJson.edges.map (({node}) => {
const {name, time, task} = node; // check here
const {name, timetable:{time, task}} = node; // this is an example of nested object destructing
return {
name,
time,
task
}
})

time and task are inside timetable nested object so the resulting code should look like:
import React from 'react'
import {useStaticQuery, graphql} from 'gatsby'
export default function Sched() {
const data = useStaticQuery(graphql`
{
allTestJson {
edges {
node {
name
timetable {
time
task
}
}
}
}
}
`)
return data.allTestJson.edges.map (({node}) => {
const {name, timetable} = node;
return <div key = {name}>
{name}
{timetable.map(item=><div key={item.task}>{item.time},{item.task}</div>)}
</div>
})
}
birthday field is not being queried (I guess it's a typo) so add it in the correct position.

Related

in map function why I cannot reach all elements?

Hello everyone I have function like that.When I tried to call my datas I can just reach to first index of each array.For example I have 5 different pictures of playstation but on my web page I just see 1 picture. How can I fix it?Is something missing in function or should change to function ?
in advance thank you
import React from 'react'
import { gql, useQuery } from '#apollo/client';
import { Image } from 'antd';
import { useState } from 'react';
const GET_TECH = gql`
query AllItem{
categories{
name
products{
name
brand
attributes{
name
id
}
gallery
category
prices{
currency{
label
symbol
}
amount
}
inStock
description
}
}
}
`;
function Tech() {
const { loading, error, data } = useQuery(GET_TECH);
if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;
console.log(data);
return (
<div className='pageLayout'>
{
(data.categories).map((item,index) => {
//const {name,brand,description,gallery,category} = item;
{
return (item.products).map((itemPrdct,subIndex) => {
const {name,brand,description,gallery,category} = itemPrdct;
if(category === "tech"){
console.log(name)
return(
<div className="tech" key = {subIndex}>
<p className='nametag' >{brand}</p>
<Image width={200} src={gallery} className='gallery'/>
</div>
)
}
})
}
})
}
</div>
)
}
export default Tech
> //Graphql structure
{
"data": {
"categories": [
{
"name": "all",
"products": [
{
"name": "Nike Air Huarache Le",
"brand": "Nike x Stussy",
"attributes": [
{
"name": "Size",
"id": "Size"
}
],
"gallery": [
"https://cdn.shopify.com/s/files/1/0087/6193/3920/products/DD1381200_DEOA_2_720x.jpg?v=1612816087",
"https://cdn.shopify.com/s/files/1/0087/6193/3920/products/DD1381200_DEOA_1_720x.jpg?v=1612816087",
"https://cdn.shopify.com/s/files/1/0087/6193/3920/products/DD1381200_DEOA_3_720x.jpg?v=1612816087",
"https://cdn.shopify.com/s/files/1/0087/6193/3920/products/DD1381200_DEOA_5_720x.jpg?v=1612816087",
"https://cdn.shopify.com/s/files/1/0087/6193/3920/products/DD1381200_DEOA_4_720x.jpg?v=1612816087"
],
console.log
I was thinking if gallery is an array then it should use map on arrays
const {name,brand,description,gallery,category} = itemPrdct;
if(category === "tech"){
console.log(name)
return(
<div className="tech" key = {subIndex}> // key can be `${idx}${subIndex}` if products are repeating
<p className='nametag' >{brand}</p>
gallery?.map((url, idx) => {
return (<Image key={idx} width={200} src={url} className='gallery'/>)
}
</div>
)
} // else { return (<EmptyElement /> } // consider returning empty element
})
// map through the image
gallery?.map((url, idx) => {
return (<Image key={idx} width={200} src={url} className='gallery'/>)
}
you can use useMemo to transform the response and filter out empty elements then map the items as needed
hope it works

How to display selected country details from data.json file on screen when select a particular country from dropdown

Data.Json
{
"countries": [
{
"name": "Australia",
"continent": "Oceania",
"rank": 4,
"id": 1
},
{
"name": "England",
"continent": "Europe",
"rank": 5,
"id": 2
},
{
"name": "Namibia",
"continent": "Africa",
"rank": 8,
"id": 3
}
]
}
CountryUI.js
import React from "react";
import { useState, useEffect } from "react";
import { connect } from "react-redux";
import { countryList } from "../actions";
const CountryUi = (props) => {
useEffect(() => {
props.countryList();
}, []);
const [country, setCountry] = useState("");
const [selectedCountry, setSelectedCountry] = useState("id");
const selectHandleChange = (e) => {
setCountry(e.target.value);
props.countries.map((countryObject) => {
console.log(countryObject);
if (countryObject.id === country) {
console.log(countryObject, "result");
setSelectedCountry(countryObject);
return countryObject;
}
});
};
return (
<div>
<h4>Select Country from below dropdown and get the details</h4>
<form className="dropdown-form">
<label className="form-labels">Select Country:</label>
<select className="select-opt" onChange={selectHandleChange}>
{props.countries.map((country) => {
return <option value={country.id}> {country.name} </option>;
})}
</select>
</form>
<div className="form-labels">Selected:{country}</div>
</div>
);
};
const mapStateToProps = (state) => {
return { countries: Object.values(state.countries) };
};
export default connect(mapStateToProps, { countryList })(CountryUi);
api/countries.js
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080",
});
Action Creator
import countries from "../apis/countries";
import { FETCH_COUNTRYLIST } from "./types";
export const countryList = () => async (dispatch) => {
const response = await countries.get("/countries");
dispatch({ type: FETCH_COUNTRYLIST, payload: response.data });
};
I have created dropdown list in React. I have used map method in order to get the list of countries which is in data.json file. It's giving me the list of countries in dropdown but I want when I select any country from dropdown list it should give me all the details which is in data.json file on screen on selecting a particular country
Instead of using setCountry (setting a state is async, so most probably it's not set yet when you map over the list), assign to a local variable (let country).
You can use Array.prototype.find to find the matching country:
const selectHandleChange = ({ target: { value }}) => {
// this will be updated in the next render
setCountry(value)
// so you should use value here
setSelectedCountry(props.countries.find(country => country.id === value))
};
and pass a value prop (country) to the select element
<select className="select-opt" value={country} onChange={selectHandleChange}>
{props.countries.map((country) => {-
// pass a unique key
return <option value={country.id} key={country.id}>{country.name}</option>;
})}
</select>
in the JSX, you should render selectedCountry
<div className="form-labels">Selected:{JSON.stringify(selectedCountry)}</div>

How to loop through array of objects in Firebase?

I'm trying to loop through an array of objects inside of Firebase, in my case I'm trying to access the data in stats, and I'm not sure how to access that value, I'm trying to use map but its giving me an error saying:
cannot read property map of undefined
Code:
// Champs
// -LIvNqyUt8Bsvrspears
// id:
// "-LIvNqyUt8Bsvrspears"
// img:
// "https://vignette.wikia.nocookie.net/leagueofleg..."
// img2:
// "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQAB..."
// name:
// "Ronaldo"
// Stats
// lvl: "medium"
// "win rate ": "51%"
// Team: "real madrid"
import React, { Component } from "react";
import { ChampsRef, timeRef } from "./reference";
import { getsinglechamp } from "../actions/champs";
import { connect } from "react-redux"; // this is not being used. oh isee so like this?
import { Redirect, Link } from "react-router-dom";
class OneChamp extends Component {
state = {
name: "",
weak: [],
img: ""
};
componentWillMount() {
const { dispatch, match } = this.props;
dispatch(getsinglechamp(match.params.id));
console.log(this.props);
}
render() {
console.log(this.props.champ);
const { dispatch, loading } = this.props;
console.log("change", this.props);
console.log(this.props.champ.stats);
let content = null;
if (loading) {
content = <p>Loading...</p>;
} else {
content = (
<div>
<div>
<h1>{this.props.champ.name}</h1>
<img src={this.props.champ.img} height="80px" />
</div>
<br />
<ul>
{this.props.champ.stats.map(stats => (
<div>
<li>{stats.lvl} </li>
</div>
))}
</ul>
</div>
);
}
return <div>{content}</div>;
}
}
const mapStateToProps = state => {
console.log("champs", state.champs);
console.log(state.loading);
return {
champ: state.champs.champ,
loading: state.loading
};
};
export default connect(
mapStateToProps,
null
)(OneChamp);
It's hard to be certain without seeing how you initialize this.props.champ.stats, but my guess is that this is a DataSnapshot you get from the Firebase Database.
While a DataSnapshot may look like an array at a glance, it does not implement Array.map(). It does however implement forEach() so you could use that to loop over the items, and then render each individually to HTML.

How to render a table with blueprintjs/table

I'm attempting to display a json array of data within a blueprintjs table. The table should be dynamic in it's rendering (number of rows and columns), so to display whatever is in the json array. In production, the json array will come from an API call, but to start off with, I'm just trying to get it working on some dummy data.
I've managed to generate the table dynamically and display the column headers, however I'm stuck on generating the actual data cells.
Here's my code so far:
interface ResultsTableProps {}
interface ResultsTableState {
numResultsRows? : number,
results
}
export default class ResultsTable extends React.Component
<ResultsTableProps, ResultsTableState> {
public state: ResultsTableState = {
numResultsRows: 0,
results: null
}
componentDidMount() {
var searchString = store.getState().submitSearch.searchString;
// Pretend an API call just happened and the results object is returned
// This is the dummy data
var resultsObject = getData();
this.setState({
numResultsRows: resultsObject.length,
results: resultsObject
});
}
private createColumn(columnData) {
return <Column name={columnData} />
}
private createColumns(columnDatas) {
return Object.keys(columnDatas[0]["_source"]).map(this.createColumn);
}
private createTable(results, numResultsRows) {
return (
<Table numRows={numResultsRows}>
{this.createColumns(results)}
</Table>
);
}
render() {
return (
<div id="results-table">
<Card interactive={false} elevation={Elevation.TWO} className={"pt-dark"}>
{this.createTable(this.state.results, this.state.numResultsRows)}
</Card>
</div>
);
}
}
When this code runs, I get a table, with the correct number of rows and the correct number of columns, and also with correct column headers.
I now need to somehow fill in the rows with the cells/data, and I'm stuck. I'm not sure how I should go about this.
How can it be done?
In case you'd like to see the dummy data:
[
{
"_type": "location",
"_id": "5sXFcmEBsayGTsLx1BqB",
"_source": {
"elevation": "",
"country": "ZA",
"geonameid": "958386",
"timezone": "Africa/Johannesburg",
"latitude": "-27.17494",
"mod_date": "2014-10-01",
"dem": "968",
"admin1_fips": "08",
"population": "0",
"alternatenames": "",
"feature_class": "S",
"geohash": "k7pt6ubwx0n0",
"name": "Sahara",
"alt_cc": "",
"fulltext": "ZA 958386 Africa/Johannesburg -27.17494 2014-10-01 968 08 0 S Sahara DC8 Sahara FRM NC083 21.91872",
"admin2": "DC8",
"asciiname": "Sahara",
"feature_code": "FRM",
"admin3": "NC083",
"longitude": "21.91872",
"admin4": ""
}
}
]
Note I'm only interested in display the data in the _source key. So the names of my columns are "elevation", "country", "geonameid", etc. And the cell data should be the values of those keys. My real dummy data actually has about 20 of these objects in the array, but i've just shown one for brevity.
Here is a more complete example.
const data = [
{foo: {bar: "baz"}},
...
]
// allows access to a deep object property by name
const getNestedProp = (obj, path) => (
path.split('.').reduce((acc, part) => acc && acc[part], obj)
)
const objectCellRenderer = (key) => (rowIndex) => {
return <Cell>{getNestedProp(data[rowIndex], key)}</Cell>
When rendering the table, define your column cellRenderer like this:
<Column name="someColumn" cellRenderer={objectCellRenderer("foo.bar")}/>
Instead of only passing they key, may pass key and value:
private createColumns(columnDatas) {
return Object.entries(columnDatas[0]["_source"]).map(this.createColumn);
}
Now you can get it like this:
private createColumn([key, value]) {
//...
}
You are just missing cellRenderer prop.
const createCell = (columnData) => (rowIndex) => {
return (
<Cell key={""}>{data[rowIndex][columnData]}</Cell>
);
};
Complete code =>
const SomeTable = () => {
const [data, setData] = useState("");
const [numDataRows, setNumDataRows] = useState(0);
useEffect(() => {
return
let fetchedData = []
// here you fetch data from somewhere
...
setData(fetchedData);
setNumDataRows(fetchedData.length);
});
}, []);
const createCell = (columnData) => (rowIndex) => {
return (
<Cell key={rowIndex + columnData}>{data[rowIndex][columnData]}</Cell>
);
};
const createColumn = (columnData, colIndex) => {
return (
<Column
name={columnData}
key={colIndex}
cellRenderer={createCell(columnnData)}
/>
);
};
const createColumns = (columnsData) => {
return columnsData ? Object.keys(columnsData[0]).map(createColumn) : [];
};
const CreateTable = (data, numDataRows) => {
return (
<Table numRows={numPlayersRows}>
{createColumns(data)}
</Table>
);
};
return <>{CreateTable(data, numDataRows)}</>;
};
export default SomeTable;

ReactJS / Javascript - Trouble Rendering Components for Items in Object

I'm having some trouble rendering components for each instance of an item in an object.
While I'm able to log the individual titles of each item, the return function doesn't return anything, regardless of which component I try to return. There are no errors, apparently.
Is there perhaps a better way of returning components according to each item in an object?
Any help would be greatly appreciated! :)
import React, { Component } from 'react';
export default class Wrapper extends Component {
const obj = () => ({
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
});
renderSingleItem(instance) {
console.log(instance); // THIS WORKS JUST FINE!
return ( // THIS DOESN'T WORK?!
<h2 key={instance.title}>
{instance.description}
</h2>
);
}
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
render() {
return (
<div>
{this.renderAllItems(this.obj)}
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
I've also attempted the following method, which actually renders a component, but only for the first item in the object.
import React, { Component } from 'react';
export default class Wrapper extends Component {
const obj = () => ({
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
});
renderSingleItem(instance) {
console.log(instance);
return (
<h2 key={instance.title}>
{instance.description}
</h2>
);
}
renderAllItems(data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
var instance = data[key];
for (var prop in instance) {
if (instance.hasOwnProperty(prop)) {
return (this.renderSingleItem(instance));
}
}
}
}
}
render() {
return (
<div>
{this.renderAllItems(this.obj)}
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
FYI, in my project, I'm importing a JSON object.
You have 2 issues in this function.
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
You need to add another return before Object.keys and you should be using .map and not .forEach since forEach is void, meaning it wont return anything.
The code should look like this.
renderAllItems(data) {
return Object.entries(data).map(([key, instance]) => {
return this.renderSingleItem(instance);
});
}
This solution worked great for me:
import React from 'react';
import { render } from 'react-dom';
export default class Wrapper extends React.Component {
constructor(props) {
super(props)
this.obj = {
"one": {
"title": "one",
"description": "foo",
},
"two": {
"title": "two",
"description": "bar",
},
};
}
renderSingleItem(instance, k) {
console.log(instance); // THIS WORKS JUST FINE!
return (<h2 key={k} children={instance.description} />);
}
/*
* Not necessary
renderAllItems(data) {
Object.entries(data).forEach(([key, instance]) => {
return this.renderSingleItem(instance);
});
}*/
render() {
return (
<div>
{Object.keys(this.obj).map((k) => {
return this.renderSingleItem(this.obj[k], k);
})}
</div>
);
}
}
// I'll leave this for you
// render(<Wrapper />, document.getElementById('root'));

Categories

Resources