Cannot Render REST API Response in react - reactjs

I am having issue with rendering the REST API response in React. I am able to see the response in console and its working there. But when I am trying to render it in UI, I am getting an error which says TypeError: Cannot read property 'State' of undefined .
I have snipped the required code and here it is.
render() {
const { getdetails } = this.state;
const itemID = 'ITAINUAT69-8982';
if (!getdetails ) {
return <div>Loading Please Wait...</div>;
}
else {
return (
<div>
{getdetails.itemID.State} // when trying to render directly, not working
// also not working in loop.
{/*
<ul>
{getdetails.itemID.map((detail, index) => (
<li key={detail.index}>
{detail.State}
</li>
))}
</ul> */}
</div>
);
}
}
}
export default Items;
Here is the response sample in Postman & console.
{
"ITAINUAT69-8982": {
"State": "Not Assigned",
"SubmitDate": "2020-09-11T04:39:51Z",
}
Thanks Everyone.

that's because in the first render getdetails is empty. you can fix this with optional chain operator:
Object.keys(getdetails)?.[0]?.State
or
getdetails?.[itemID]?.State

Related

How to implement error boundaries in react with MERN?

My goal is to simply dynamically present the data from a mongo database of a specific document.
const Details = () => {
const { id } = useParams()
const [product, setProduct] = useState(null)
useEffect(() => {
const fetchProduct = async () => {
const response = await fetch(`/api/products/${id}`)
const json = await response.json()
if (response.ok) {
setProduct(json)
console.log(json)
}
}
fetchProduct()
}, [id])
this code works fine as it gets the product, but my problem is occurring with the rendering:
return (
<div className="details">
<Menu />
<h1 className="movement">Product Details - {product.name}</h1>
</div>
);
}
the error that I'm getting is Uncaught TypeError: Cannot read properties of null (reading 'name') and to Consider adding an error boundary to your tree to customize error handling behavior.
my question being is how do i implement correct error handling
Just use the optional chaining operator:
product?.name
It's typical that in the first render product is not yet available so you cannot access to any of its properties. With the optional chaining operator you are covering this case.
See more: https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Operators/Optional_chaining
If you want to add Error Boundaries:
https://reactjs.org/docs/error-boundaries.html#gatsby-focus-wrapper
React renders the component before you make an api request, thus product doesn't exist (it's null based on how you set its initial value). Then when response is received you set product to state and react re-renders your component. Now product exists.
To solve it, render h1 only when product exist.
<div className="details">
<Menu />
{ product && <h1 className="movement">Product Details - {product.name}</h1> }
</div>
Also, you can render a message if product is not yet exist
<div className="details">
<Menu />
{ product && <h1 className="movement">Product Details - {product.name}</h1> }
{ !product && <p>Loading ... </p>
</div>

Cannot return the content from a nested array in React JS

I am trying to display the data I fetched from an API which is a nested array. The json file looks like this for one pool and the devices inside that pool:
[
{
"id": "staging",
"pool": "some name",
"status": "FAILED",
"deviceMonitoringEntries": [
{
"deviceDescriptor":{
"id": "Apple_TV_HD1",
}
]
}
]
I want to display the id of the pool first and then display the devices assigned to the pool by displaying the id in deviceDescriptor.
My code is like this:
import React, { useEffect, useState } from 'react'
import axios from 'axios'
function Pool(){
const url = 'http://localhost:8043/pools'
const [pool, setPool] = useState(null)
let content = null
useEffect(() => {
axios.get(url)
.then(response =>{
setPool(response.data)
})
}, [url])
if(pool){
console.log("in if pool")
console.log(pool)
return (
content=
<>
{pool.map((id) => {
<h3 key = {id}>{id}</h3>
return (
<>{pool.map(({ deviceMonitoringEntries}) => (
deviceMonitoringEntries.map((deviceDescriptor) => (
<p key = {deviceDescriptor.id}> {deviceDescriptor.id}</p>
))
))}</>
);
})}
</>
)
}
return(
<div>
{content}
</div>
)
}
export default Pool
However, the header <h3 key = {id}>{id}</h3> never prints. I can display the header and paragraph separately but it does not work together. I am very new to React and I would appreciate your help!
As per React documentation
React components implement a render() method that takes input data and returns what to display.
In the functional component, you directly add a return statement at the end.
You cannot assign variables like this in your code.
return (
content=
<>
...
</>
You got the response and you stored that value in a state variable. Use the variable and render your content in the final return statement.
{
pool.map((p) => (
<>
<h3 key={p.id}>{p.id}</h3>
{p.deviceMonitoringEntries.map((device) => (
<p key={device?.deviceDescriptor?.id}>{device.deviceDescriptor?.id}</p>
))}
</>
));
}
You can try like that in your code and I am attaching a sandbox for reference here.

Unable to render data in Reactjs

I am new to react and have been debugging this from yesterday and I finally decide to post as I am clueless of what is happening.
The following react code fetches data from the api and then renders it on the UI. But, there are few strange things happening here.
I get error saying as TypeError: Cannot read property 'map' of undefined initially but when I comment out {renderTableData(data)}& save and then again uncomment & save, the data is rendering perfectly on the UI
I am thinking that before even the data gets fetched from API, it is getting passed to the function renderTableData which is why in the console undefined is printed.
Here is the code
export default function TenantList(){
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users').then((response)=>{
return response.json();
}).then((data)=>{
setData(data)
})
},[]);
function renderTableData(data) {
console.log("hello ", data)
return data.map((student, index) => {
const { name, email } = student //destructuring
return (
<tr key={name}>
<td>{name}</td>
<td>{email}</td>
</tr>
)
})
}
return (
<>
<div>
{renderTableData(data)}
</div>
</>
)
}
Please suggest a workaround
You only want to run this function if you have the data, so check for it:
{data && renderTableData(data)}

How to use getquery with amplify <Connect/> component in React

I have been trying to use the together with a getquery in react but I can't get it to work. Below is the code I put together
const input = {
id: this.props.Id
};
return (
<div>
<Connect
query={graphqlOperation(getRecords, input)}
subscription={graphqlOperation(onCreateRecords)}
onSubscriptionMsg={onNewRecord}
>
{({data, loading, error}) => {
if (loading) return "Loading"
if (error) return "Error"
const ListRecord = data.getRecords
console.log('ListRecord', ListRecord)
//console.log returns undefined
return <div>...
</div>
}}
</Connect>
</div>
Deos anyone know what I'm doing wrong? Thanks!
It's hard to say based on what you've posted alone. Is there any additional information in the 'data' object?
Also, Have you tried doing:
query={graphqlOperation(getRecords, {input})}

React - Iterating over State to dynamically generic element

This is a pretty basic question but I've been struggling; Likely due to my 'not quite understanding' how .map() works, and when to make an Object an array etc.
import React, { Component } from 'react';
import Post from './Post/Post';
class Posts extends Component {
state= {
posts: [
{
title: "Test",
content: "Some content"
},
{
title: "Test2",
content: "Some Additional Content"
}
]
};
render() {
let post = null;
post = Object.keys(this.state.posts).map(function (item, key) {
return <Post title={this.state.posts[item].title} content={this.state.posts[item].content} />
})
return (
<div>
<div>List of Posts</div>
{post}
</div>
);
}
}
export default Posts;
This is where I settled, since I got my JSBin version to work. However I'm getting a warning on my 'anonymous callback' function that creates the <Post> elements. <Post> is just expecting those two props and rendering them. I'm getting a warning on line 26 that mentions state being undefined. Am I not initializing state properly?
post = this.state.posts.map(function (item, key) {
return <Post title={item.title} content={item.content} key={key}/>
})
Your state.posts is an array and you should map over it.
post = Object.keys(this.state.posts).map((item, key) => {
return (
<Post
title={this.state.posts[item].title}
content={this.state.posts[item].content}
/>
)
})
as Subin says, what you need to do in that case is just map over the posts array.
But, to fix your code is very simple. just use arrow function instead of a regular function.
Do it like this:
post = this.state.posts.map(post => {
return <Post title={post.title} content={post.content} key={post.title}/>
})
When you map over array, you dont need to acces that state again, because post will be assigned to post inside map function. And then just acces title and content. and dont forget to pass key,there i've passed key={post.title} but that is not a good solution, because it needs to be unique.

Resources