Nested JSON Objects in React JS - reactjs

I have a API Response which has two Arrays - Incident and Services.
I have two Buttons "Incident" & "Service Req.", Once we click on each button it should get a list of Incident or Service Req with toggle or disabled MUI button functionality.
I'm trying to create two buttons - Incident & Service Req
Once we click on Incident/Service Req button we need - Inc/SR list on same Container DIV
Im trying to add MUI Disabled button or Toggle Functionality but my basic Functionality is not working.
{
"totalIncident": 20,
"totalRequests": 20,
"incidents": [
{
"createdOn": "2022-10-20 07:14:17",
"description": "This is Incident .",
"number": "REQ9XXXX"
}
],
"requests": [
{
"createdOn": "2022-10-20 07:14:17",
"description": "This is Request.",
"number": "REQ9XXXX"
}
}
]
}
import React from "react";
import "./App.css";
class API_APP extends React.Component {
constructor() {
super();
this.state = { data: [] };
}
componentDidMount() {
fetch(
"API_LINK"
)
.then((res) => {
return res.json();
})
.then((resp) => {
this.setState({ data: resp });
console.log(resp);
});
}
onClickIncidents = () => {
console.log(this.state.data.incidents);
return (
<div>
<h1>Incidents</h1>
{this.state.data.incidents?.map((item) => {
return (
<div key={item.sysId} className="part">
<li> {item.number}</li>
</div>
);
})}
</div>
);
};
render() {
console.log(this.state.data);
const incidents = this.onClickIncidents;
console.log(incidents);
return (
<div className="container">
<h1>Incidents</h1>
<button onClick={this.onClickIncidents}>incidents</button>
<button onClick={this.onClickRequests}>requests</button>
</div>
);
}
}
export default API_APP;

Related

REACT GET requiest getting base url twice

Using REACT front-end with Django back-end. When i call request api i can see it being pulled correctly, however when onClick is called i get a 404 XHRGEThttp://localhost:3000/http//127.0.0.1:8000/undefined so it seems that i am somehow calling the base url twice but i am not sure how?
here is my main component file:
import React, { Component } from 'react';
import SubtagsList from './list_subtags';
import axios from 'axios';
class TagsList extends Component {
constructor(props) {
super(props);
this.state = {
tagData: [],
subtags: " ",
showComponent: false,
}
this.getSubtagDetail = this.getSubtagDetail.bind(this);
this.showSubtags = this.showSubtags.bind(this);
}
getSubtagDetail(item){
axios.get("http//127.0.0.1:8000/".concat(item.absolute_url))
.then((response) =>{
this.setState({subtags: response.data})
})
.catch(function(error){
console.log(error);
})
}
showSubtags(item){
this.getSubtagDetail(item);
this.setState({showComponent: true})
}
componentDidMount(){
axios.get("http://127.0.0.1:8000/")
.then( (response) => {
this.setState({tagData: response.data})
})
.catch(function(error) {
console.log(error);
})
}
render() {
return (
<div>
{this.state.tagData.map((item) => {
return (
<h3 key={item.id} onClick={() => this.showSubtags(item)}>
{item.tag_name}
</h3>
);
})}
{this.state.showComponent ? (
<SubtagsList subtagDetail={this.state.subtags} />
) : null}
</div>
)
}
}
export default TagsList;
here is the api response:
[
{
"id": 2,
"tag_name": "IT/Computer Issues",
"type": "Tag"
},
{
"id": 1,
"subtag_name": "Website",
"absolute_url": "/1",
"type": "SubTag"
}
]
and this is the SubtagsList component imported:
import React, { Component } from 'react';
class SubtagsList extends Component {
render() {
const obj = this.props.subtagDetail;
return (
<div style={{ color: "yellow", border: "1px solid yellow" }}>
<p>{obj.subtag_name}</p>
</div>
)
}
}
export default SubtagsList;
Can anyone shed some light on what i might be doing wrong here?

How to pass data to props from state?

I'm learning React and have some troubles with using state and props. There is two files: App.js and component. In App.js i use axios to get JSON data from IP and store in a state. But I cannot pass the data to props through the state.
Here is App.js:
import React from 'react';
import axios from 'axios';
import Shutruk from './Shutruk';
const qwerty = {
"data": [
{
"_id": "5d1cb18e4af03042df6267c5",
"title": "Shutruk",
"description": "Shhhhhhhhhhhhh",
"date": "2019-07-03T13:45:50.850Z",
"__v": 0
},
{
"_id": "5d1cc27b37c9751001f5c12f",
"title": "Shilkhak",
"description": "Shilkhak-Inshushinak",
"date": "2019-07-03T14:58:03.797Z",
"__v": 0
},
{
"_id": "5d1cc45655780f11112a023f",
"title": "Унташ",
"description": "Untash-Napirisha",
"date": "2019-07-03T15:05:58.699Z",
"__v": 0
},
{
"_id": "5d1ef36c503601183b5f856f",
"title": "dgfdgfdhgf",
"description": "bbbbbbbbbbbbbbbbb",
"date": "2019-07-05T06:51:24.873Z",
"__v": 0
},
{
"_id": "5d1ef381503601183b5f8570",
"title": "qewytuytruytru",
"description": "jhfgasjdfgasjdfgjhsdf",
"date": "2019-07-05T06:51:45.761Z",
"__v": 0
}
]
};
class App extends React.Component {
state = {
data: []
}
componentDidMount() {
axios.get('http://localhost:5555/posts')
.then(res => {
const data = res.data;
this.setState({ data });
})
}
render() {
return (
<div>
<Shutruk name={ this.state.data.data[0].title }/>
</div>
)
}
}
export default App;
Here is the component:
import React from 'react';
class Shutruk extends React.Component {
render() {
return (
<div>
<h1>This is is {this.props.name}!</h1>
</div>
)
}
}
export default Shutruk;
I use axios to get data from backend, but when I insert it to props, it does'nt work. I create an array qwerty[] with the same data, and when I replace with:
return (
<div>
<Shutruk name={ qwerty.data[0].title }/>
</div>
)
it works correctly. What is the problem, if there is no difference between 'this.state.data' and 'qwerty'?
I checked with console.log and the result is same!
Thanks to everyone for any help!
This is because, axios and setState are asynchronous and when the component loads in componentDidMount, it takes a while to load data into state and since data.data[0] is still empty, it doesn't work. But when you use a const to declare it, it works as it is already present.
Instead of
<Shutruk name={ this.state.data.data[0].title }/>
Do:
renderShutruk = () => {
if (this.state.data.data !== undefined) {
return <Shutruk name={this.state.data.data[0].title} />
} else {
return null;
}
};
render() {
return (
<div>
{this.renderShutruk()}
</div>
);
}
Your App component is probably crashing when mounting while you're accessing an undefined state because your try to get this.state.data.data[0].title when data state equals []
Try replacing your App component like this to prevent access to an undefined state (I recommend doing this for all your asynchronous operations in the components):
class App extends React.Component {
state = {
data: [],
loading: true,
error: false,
}
componentDidMount() {
axios.get('http://localhost:5555/posts')
.then(res => {
const data = res.data.data; // get the data array instead of object
this.setState({ data, loading: false });
})
.catch(err => { // log request error and prevent access to undefined state
this.setState({ loading: false, error: true });
console.error(err);
}
render() {
if (this.state.loading) {
return(
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
return(
<div>
<p> An error occurred </p>
</div>
)
}
return (
<div>
<Shutruk name={ this.state.data[0].title }/> // access to data array state
</div>
)
}
}
export default App;
Just change this,
<Shutruk name={ this.state.data.data[0].title }/>
with,
{this.state.data ? <Shutruk name={ this.state.data[0].title }/> : null}
Update
If you are not getting data, then you must use async/await,
async componentDidMount() {
await axios.get('http://localhost:5555/posts')
.then(res => {
//console.log(res) => if `res` is {data:[...]} , then do this,
const data = res.data;
//console.log(res) => if `res` is {data: data: [...]} , then do this,
const data = res.data.data;
this.setState({ data });
})
}

Is it possible to make a state array from this JSON object?

A newbie in React here. I'm using axios to retrieve this object requested to my Django server rest framework Api:
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"url": "http://localhost:8000/blog/api/categories/1/",
"title": "Django",
"slug": "django"
},
{
"id": 2,
"url": "http://localhost:8000/blog/api/categories/2/",
"title": "Git",
"slug": "git"
},
{
"id": 3,
"url": "http://localhost:8000/blog/api/categories/3/",
"title": "Introduction to docker",
"slug": "introduction-to-docker"
}
]
}
So far I've been able to store those variables in separate arrays. This is the implementation of my FetchDemo.js:
import React, {Component} from 'react';
import axios from 'axios';
{/* https://daveceddia.com/ajax-requests-in-react/ */}
class FetchDemo extends Component {
state = {
urls: []
}
state = {
titles: []
}
state = {
slugs: []
}
componentDidMount() {
axios.get(`${this.props.url}${this.props.path}`).then(res => {
const urls = res.data.results.map(num => num.url);
const titles = res.data.results.map(num => num.title);
const slugs = res.data.results.map(num => num.slug);
this.setState( {urls} );
this.setState( {titles} );
this.setState( {slugs} );
});
}
render() {
return (
<div>
<h1>{`${this.props.url}${this.props.path}`}</h1>
<ul>
/// How to generate the JSX objects? ///
</ul>
</div>
);
}
}
export default FetchDemo;
Is it possible to build in the axios request a state array from this JSON object like the next one instead? How do I generate JSX with this new state categories?
this.setState({
categories: [
{url: "http://localhost:8000/blog/api/categories/1/", title: "Django", slug: "django"},
{url: "http://localhost:8000/blog/api/categories/2/", title: "Git", slug: "git"},
{url: "http://localhost:8000/blog/api/categories/3/", title: "Introduction to Docker", slug: "introduction-to-docker"},
]
}
)
I wish I knew more React and JavaScript. Any help is appreciated, thanks in advance.
There are a few things to note here.
state is a single object with multiple keys.
setState() is a single async transaction. When you are updating your state, you should update it in one go.
You can do things in a simpler way if I understand your question right. You don't have to store the values in multiple keys. It can be stored in a single key categories.
import React, { Component } from 'react';
import axios from 'axios';
class FetchDemo extends Component {
constructor(props) {
super(props);
this.state = {
categories = []
}
}
componentDidMount() {
axios.get(`${this.props.url}${this.props.path}`).then((res) => {
const urls = res.data.results.map((num) => num.url);
const titles = res.data.results.map((num) => num.title);
const slugs = res.data.results.map((num) => num.slug);
this.setState({
categories: res.data.results
});
});
}
render() {
const { categories } = this.state;
return (
<div>
<h1>{`${this.props.url}${this.props.path}`}</h1>
<ul>
{categories.length ?
categories.map(cat => (
<li key={cat.id}>
<div>{cat.title}</div>
</li>
))
:
(<li>categories not loaded yet</li>)}
</ul>
</div>
);
}
}
export default FetchDemo;

How to get an item from an array in JSON in ReactJS?

I am trying to get an item "icon" from "weather" form following JSON
{
"coord": {
"lon": 14.33,
"lat": 49.94
},
"weather": [{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}]
}
I can't figure out how to exctract an item which is in array through render method.
My code is:
class Weather extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch('http://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4')
.then(results => results.json())
.then(results => this.setState ({'items': results}));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>
})}
</div>
);
}
}
I actually used this question here: Get access to array in JSON by ReactJS ...which got me this far, but still can't make it working...
Your weather array is not set until your fetch request is complete, so this.state.items.weather.map in your render method will result in an error.
You could give weather an empty array as default value.
class Weather extends React.Component {
constructor() {
super();
this.state = {
items: {
weather: []
}
};
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch(
"http://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4"
)
.then(results => results.json())
.then(results => this.setState({ items: results }));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>;
})}
</div>
);
}
}
copy paste this example in codesandbox.io .you were initializing the items in constructor as array(where as fetch gave you an object) and for the initial render, items.weather was undefined and in render method you were trying to access map of undefined which was causing the error. (I have changed the url to https to run it in codesandbox)
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
items: {}
};
}
componentDidMount() {
this.getItems();
}
getItems() {
fetch(
"https://api.openweathermap.org/data/2.5/weather?lat=49.9415967&lon=14.3316786&appid=ed62e370682cc9e4144620905eff37e4"
)
.then(results => results.json())
.then(results => this.setState({ items: results }));
}
render() {
return (
<div>
<h1>here should be an icon..</h1>
{this.state.items.weather &&
this.state.items.weather.map(function(weather, index) {
return <h3 key={index}>{weather.icon}</h3>;
})}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Why declearing function(Element) outside render doesn't work?

I want to create a dynamic Element inside parent Component class. It gives Unexpected token at function declaration. However writing same function inside return(..here..) works. What am I missing?
This is my code:
import React, { Component } from 'react';
import '../App.css';
var axios = require('axios');
class DisplayRevenue extends Component {
constructor(props){
super(props);
this.state = { data:[] }
}
componentWillMount() {
this.loadRevenue(this.props.url, this.props.token);
}
setData(data){
this.setState(data:data);
console.log(this.state.data); //this gives output as json object
}
loadRevenue(url,token){
axios({
method:'get',
url:url,
headers: {
Authorization: `Bearer ${token}`,
},
})
.then( (response) => {
// console.log(response.data);
this.setData(response.data);
})
.catch(function (error) {
console.log("Error in loading Revenue "+error);
});
}
var ListData = this.state.data.map( (invoice) => {return <div>{invoice.customerNumber}</div>})
//above function gives error
render() {
//var listData = this.state.data.map( (invoice) => (<div>{invoice.customerNumber}</div>)
return (
<div>
<h3>MonthToDate</h3>
{this.state.data.map((invoice) => {return <div>{invoice.customerNumber}</div>})}
</div>
);
}
}
export default DisplayRevenue;
I have json object array as below:
"data": [
{
"customerId": 0,
"customerNumber": "IT8SDS",
"customerType": "RVN",
"invoiceType": "LBR",
"invoiceAmt": "52651.2287",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 1,
"customerNumber": "DC0WTY",
"customerType": "RVN",
"invoiceType": "RNT",
"invoiceAmt": "198503.1828",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 2,
"customerNumber": "LK8MD5",
"customerType": "INT",
"invoiceType": "EQT",
"invoiceAmt": "-6833.70721",
"invoiceStatus": "PENDING",
"invoiceDate": "2016-12-30T00:00:00.000Z"
},
{
"customerId": 3,
"customerNumber": "E03PTJ",
"customerType": "PCT",
"invoiceType": "PTS",
"invoiceAmt": "55670.17911",
"invoiceStatus": "BILLED",
"invoiceDate": "2016-12-19T00:00:00.000Z"
},
NOTE: Writing {this.state.data.map((invoice) => {return <div>{invoice.customerNumber}</div>})} inside return(..here..) in render() works.
You can't declare variables inside a class body.
You can do that inside functions (such as render, constructor, react life cycle methods, custom functions etc...).
If you want to do it the "react way" make ListData as a component:
Example:
const ListData = data => (
<div>
{data.map( (invoice) => <div>{invoice.customerNumber}</div>)}
</div>
);
And use it like so:
render() {
return (
<div>
<h3>MonthToDate</h3>
<ListData data={this.state.data} />
</div>
);
}
Here is a working example:
const ListData = ({data}) => (
<div>
{data.map((o) => (<div>{o}</div>))}
</div>
);
const App = () => (
<div>
<h2>Hello</h2>
<ListData data={["Hi", "i'm", "a", "test"]} />
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
<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>
<div id="root"></div>

Resources