Accessing nested JSON data with React Hooks & Props - javascript

I'm trying to access data further down into my JSON file. I am able to easily access data in the first two data sets in rows and area:
data.json
"rows": [
{
"uid":"001",
"type": "Lorem ipsum",
"area": [
{
"name": "London",
"number": "12345",
"wait": {
"start": {
"start_time": 1585129140,
"delay": 300
},
"end": {
"end_time": 1585130100,
"delay": 300
}
},
"in": 1585129140,
"out": 1585130100,
},
However when I try to access the data under wait which includes this block:
"wait": {
"start": {
"start_time": 1585129140,
"delay": 300
},
"end": {
"end_time": 1585130100,
"delay": 300
}
},
No data is getting returned on screen from my jsx file, but it is available in the console log
TimeTracker.jsx
const TimeTracker = (props) => {
const trainTime = useState(props.data);
console.log(props.data);
return (
<>
<div className={style.timeLabel}>
<div className={style.startTime}>{trainTime.start_time}</div>
<div className={style.endTime}></div>
</div>
</>
)
};
export default TimeTracker;
console.log
wait:
start:
start_time: 1585129140
delay: 300
__proto__: Object
end:
end_time: 1585130100
delay: 300
__proto__: Object
__proto__: Object
I've used the same pattern for passing props in other components and it works fine on the first two levels so I don't understand why it's not working. How do I get data from further in this JSON?

useState returns a tuple with the object and a function to set the value on the object. You probably need to change your component to something like this:
const TimeTracker = (props) => {
const [trainTime, setTrainTime] = useState(props.data);
console.log(props.data);
return (
<>
<div className={style.timeLabel}>
<div className={style.startTime}>{trainTime.start_time}</div>
<div className={style.endTime}></div>
</div>
</>
)
};
export default TimeTracker;

A nested property can not be accessed by one level of a.b so instead of
<div className={style.startTime}>{trainTime.start_time}</div>
it should be
<div className={style.startTime}>{trainTime.wait.start.start_time}</div>

Related

Accessing nested array in an object returning undefined

I'm having trouble accessing the values of a nested array and I've been stuck on it for days, hoping someone can help!
I've just started learning React and i'm working on an app that fetches the data from Wordpress using graphql and apollo
The array structure when I console my data:
{__typename: 'Yarn', name: 'Brick Red', yarnFields: {…}}
name: "Brick Red"
yarnFields:
yarnColor: "#cb4154"
yarnFiber: Array(1)
0: {__typename: 'Fiber', name: 'Merino'}
length: 1
[[Prototype]]: Array(0)
yarnPrice: 6.5
__typename: "Yarn_Yarnfields"
[[Prototype]]: Object
__typename: "Yarn"
[[Prototype]]: Object
The array structure from graphql:
{
"data": {
"yarns": {
"nodes": [
{
"name": "Brick Red",
"id": "dGVybToyNTI=",
"yarnFields": {
"yarnColor": "#cb4154",
"yarnPrice": 6.5,
"yarnFiber": [
{
"name": "Merino"
}
]
}
},
{
"name": "Burgundy",
"id": "dGVybToyNzg=",
"yarnFields": {
"yarnColor": "#662d40",
"yarnPrice": 9.11,
"yarnFiber": null
}
},
{
"name": "Cobalt Blue",
"id": "dGVybToyOTQ=",
"yarnFields": {
"yarnColor": "#1664af",
"yarnPrice": 7.54,
"yarnFiber": null
}
},
etc
I can get all the other values by using this syntax:
{yarn?.yarnFields?.yarnPrice}
the value i need to get is yarnFiber.name ( in the case the value is "Merino")
but when i use the same syntax for yarnFiber it returns undefined
My JSX Code to map through the JSON object:
const { loading, error, data } = useQuery(YARNS_QUERY);
if (isEmpty ( data )){
return null;
}
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<>
{data.yarns.nodes.map((yarn, i) => (
<DK key={i} yarn={yarn}/>
))}
My Component where I display the yarn info:
return (
<div>
<div onClick={change}
data-color={yarn?.name}
data-price={yarn?.yarnFields?.yarnPrice}
data-fiber={yarn?.yarnFields?.yarnFiber?.name}
style={{
background:yarn?.yarnFields?.yarnColor,
width: '50px',
height: '50px',
// border:'5px dashed #2d2e2e',
borderRadius: '50%'}}>
fiber: {yarn.yarnFields?.yarnFiber?.name} // returns empty
</div>
</div>
);
I've tried mapping through the nested array but i can't seem to get the syntax correct to fit my code. i'm not even sure if thats what i need to do!
Any help appreciated but would love the solution in detail as I'm a total noob!
UPDATE:
the yarnFiber array has multiple values that need to be displayed
"name": "Burgundy",
"id": "dGVybToyNzg=",
"yarnFields": {
"yarnColor": "#662d40",
"yarnPrice": 9.11,
"yarnFiber": [
{
"name": "Merino Wool"
},
{
"name": "Silk"
},
{
"name": "Cashmere"
}
]
}
},
how should i reflect this in my code?
thanks again
yarnFiber is an array so you need to reference its objects by index:
fiber: {yarn.yarnFields?.yarnFiber && yarn.yarnFields?.yarnFiber.length > 0
? yarn.yarnFields?.yarnFiber[0].name
: 'No fiber'
}
If you need to display all names in the array you can just map through them:
{
yarn.yarnFields?.yarnFiber && yarn.yarnFields?.yarnFiber.length > 0
? yarn.yarnFields?.yarnFiber.map((fiber, index) => (
<div key={index}>{fiber.name}</div>
))
: 'No fibers';
}

Display individual elements from array in React

Been trying all morning and for the life of me I can't get individual array data to be displayed from my API. I am trying to display one body of text from an array at a time, and can only get it to output all at once. Had it working when the data was in JSON format but now its in an array I'm struggling to make it work.
My code:
componentDidMount() {
axios
.get(
"API_DATA"
)
.then((res) => {
let data = res.data
this.setState({ data, loading: false });
console.log(data)
});
}
render() {
if (this.state.loading) {
return <Loader />
}
// return table if loading is false
// handling error goes with the same logic
// table will only render if loading is false
else
return (
this.state.data.data).map((item) => (
<>
<p key={item.id}>{item.title}</p>
</>
))
}
}
I previously used added [0] or [1] etc to determine which element I wanted to display and this worked very nicely however if I try this.state.data.data[0]).map((item) => ( It states it is not a function.
Expected output of API:
{
"data": [
{
"id": 9,
"status": "published",
"body": "TEST1",
"availability": "internal",
"title": "Test1",
"posted_by": "Tester"
},
{
"id": 10,
"status": "published",
"body": "TEST",
"availability": "internal",
"title": "TEST2",
"posted_by": "Tester"
},

Where am i going wrong with this array filter? Reactjs

I am mapping over some data that I am getting from a api however when i try to add the filter function i get 'currencyData.includes is not a function'
I have also tried just hard coding the array but it also still doesnt work?
I have a loading state for when i fetch data from the api which holds code from being run but i have removed it from this example as its not getting data from the api below.
The simplified version is here...
ARRAY
var items = [
{
"id": 1,
"productName": "shoes",
"productIdentifier": "CL001",
"productDescription": "adidas kicks boir",
"productPrice": 2000,
"productStock": 200,
"created_at": "2020-51-28",
"updated_at": null
},
{
"id": 2,
"productName": "burger",
"productIdentifier": "FD001",
"productDescription": "charsiu berger",
"productPrice": 2000,
"productStock": 200,
"created_at": "2020-51-28",
"updated_at": null
}
]
return(
{items.filter(currencyInfo => currencyInfo.includes("FD001")).map((value, index) => {
console.log(value)
return(
<h1 key={index}>{value}</h1>
)
})}
)
currencyInfo is not an array, you can not call includes on it
Here is my suggestion:
return(
{items.filter(currencyInfo => currencyInfo.productIdentifier === "FD001").map((value, index) => {
console.log(value)
return(
<h1 key={index}>{value}</h1>
)
})}
)
More about includes()
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate. Check this Doc
But in items.filter(currencyInfo => currencyInfo.includes("FD001")), type of currencyInfo isn't array but object.
So you should use currencyInfo.productIdentifier.includes()

React cannot map through prop array

I fetch an api on componentDIdMount() then store the json to a state then I pass that state as a prop, I have no problem showing the data except on arrays.
<Component details={this.state.details} />
json:
{
"adult": false,
"backdrop_path": "/qonBhlm0UjuKX2sH7e73pnG0454.jpg",
"belongs_to_collection": null,
"budget": 90000000,
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 878,
"name": "Science Fiction"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 10751,
"name": "Family"
}
]
}
then I try to map the genres:
<div className={style.genre}>
{details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
</div>
But then I get Cannot read property 'map' of undefined, I don't know why this is happening because I'm able to do details.budget
It's trying to read data before you get the result from api.
so write the map function as
{details&&details.genres&&details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
In react Initially when component is mounted, render() function is called and then componenentDidMount() is called in which you fetch data. So Initially details is empty. So you need to write the condition.

Generating components through iteration

Something weird is going on:
This is my initial state (a .js file)
import moment from 'moment';
let date = moment();
var previousDate = moment("2015-12-25");
export const projects = [
{
"id": 0,
"metadata": {
"fields":
[{
"id": 1,
"order": 1,
"name": "Name",
"value": "Collection 1"
},
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate
},
{
"id": 4,
"order": 4,
"name": "Status",
"value": "Filed"
}],
"tags":
[{
"id": 1,
"order": 1,
"value": "tag1"
},
{
"id": 2,
"order": 2,
"value": "tag2"
},
{
"id": 3,
"order": 3,
"value": "tag3"
},
{
"id": 4,
"order": 4,
"value": "tag4"
}]
}
}
This is ProjectsList.js:
import React from 'react';
import Project from './Project';
import { projects } from 'initialState';
export default (props) => {
return(
<div className="projectsList">
{projects.map(project => (
<article key={project.id}><Project fields={project.metadata.fields} /></article>
))}
</div>
)
}
And this one's Project.js:
import React from 'react';
export default (props) => {
return(
<ul className="fields">
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
</ul>
)
}
I am trying to render a bunch of projects in a list, and every project contains a bunch of metadata key-value pairs that it shows.
So basically, the wiring does not matter, it all works fine.
Except for this:
If you look up at the initial state file (first one up there), there is an array of multiple objects in fields. Each object shows 4 key-value pairs
id
order
name
value
Now, in Project.js, the line where I go
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
looks like I can switch the {field.name} for {field.id}, to show the id in text. Or I can go {field.order}, to display the order.
But weirdly enough, if I want to show the actual value of the field, like so {field.value}, it throws.
invariant.js?4599:38
Uncaught Invariant Violation: Objects are not valid as a React child (found: Mon Jun 20 2016 21:40:33 GMT-0400). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `StatelessComponent`.
I even went as far (sigh) as changing the string value in every fields to val, juste to make sure value wasn't some kind of a reserved word.
Still threw.
Anybody can help me understand what I have done wrong, here?
Thanks Guys.
You are assigning to variable values to the value property in your state file, which are most likely not strings, but objects:
export const projects = [{
"id": 0,
"metadata": {
"fields":
[
...
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date // one
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate // and another one
},
...
]
...
}
}
If typeof children returns "object" (and children is neither an array, nor a ReactElement), it throws:
https://github.com/facebook/react/blob/dc6fc8cc0726458a14f0544a30514af208d0098b/src/shared/utils/traverseAllChildren.js#L169
Here's a simplest example to demonstrate this:
const IllegalComponent = () => <span>{{}}</span>
You are supposed to supply a string (or number) so that React could inline that as the children in <li>. Children should be something that's renderable and implements ReactNode.
If the children is an object, React would not know how to render it. You should explicitly convert the value to String.
Try this to see if it works:
{props.fields.map(field => <li key={field.id}>{field.value.toString()}</li>) }

Categories

Resources