How to loop through the state in react - reactjs

I have a class named List and i recived some data from api and i had put it into state and i am reviving this data
(6) [{…}, 200, "OK", {…}, {…}, XMLHttpRequest]
0:
0: {id: "1", name: "vivek", fname: "manohar", mobile: "8824859583", photo: "http://localhost/freact/uploaded/student/194_axixa_cleaner-better-code-670x335.jpg"}
1: {id: "2", name: "anki", fname: "Sushil", mobile: "267877", photo: "http://localhost/freact/uploaded/student/382_axixa_Ankita.pdf"}
__proto__: Object
1: 200
2: "OK"
3: {content-type: "text/html; charset=UTF-8", content-length: "312"}
4: {url: "http://localhost/freact/index.php", method: "post", data: FormData, headers: {…}, transformRequest: Array(1), …}
5: XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
length: 6
How i can print this data in table format which i am recieving
My code to retrieve data from api is
componentDidMount(){
const sendData = new FormData();
const thiss=this;
sendData.append('func','list');
sendData.append('qry','select * from student');
axios.post("http://localhost/freact/index.php",sendData)
.then(
(resp)=>{
Object.keys(resp).forEach(function(key) {
thiss.arr.push(resp[key]);
});
this.setState({data:this.arr});
}
)
}

You can achieve that with map
Try to write your code like this:
<table>
<thead><tr><th>title</th></tr>
</thead><tbody>
{ this.state.mydata.map(x =>
<tr><td>{x.title}</td></tr>}
</tbody>
</table>
Or you can start without using table to make it simpler to understand.
<div>
{this.state.yourstatename.map
(Myanyname=>
<div>{Myanyname.yourfield}</ div>
}
</div>
(For your code you should change fields,for example you dont have title field in your data)
If you want more specific hel,you should share your react code as well
I hope you get the idea and works for you

Assuming you are storing the data in variable named data
You can try
renderTable = () => (
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Fname</th>
<th>Mobile</th>
<th>Photo</th>
</tr>
</thead>
<tbody>
{this.state.data.map(rowData => (
<tr key={rowData.id}>
<td>{rowData.id}</td>
<td>{rowData.name}</td>
<td>{rowData.fname}</td>
<td>{rowData.mobile}</td>
<td>{rowData.photo}</td>
</tr>
))}
</tbody>
</table>
)
If you don't want to render plain text in table body and want to use a element like <img> or <div> you can try that too in <td/> like
<td><img src={validSource} alt="alt" /></td>
Call the same renderTable function in render method as below
render() {
return(
<div>
{this.renderTable()}
</div>
)
}

If you want to get response only:
const sendData = new FormData();
sendData.append('func','list');
sendData.append('qry','select * from student'); // atencion at slq injection here
Fertch with axios:
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
axios.post('http://localhost/freact/index.php',sendData,config).then(response => this.setState({ users: response.body }));
Fetch with fetch:
fetch('http://localhost/freact/index.php', {
method: 'POST',
body: formData
}).then((r) => {
const contentType = r.headers.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) {
return r.json().then(data => ({status: r.status, body: data}));
} else {
return r.text().then(text => ({status: r.status, body: text}));
}
}).then((res) => {
if (res.status == 200) {
// do something
this.setState({ users: res.body })
} else {
// handle error
console.warn(res.body.message)
}
}).catch((err) => {
console.log(err);
});
in render:
render() {
const { users } = this.state
return (
<div>
<table>
<thead>
....
</thead>
<tbody>
{
users.map(user => {
return <tr>
<td>{user.name}</td>
...
</tr>
})
}
</tbody>
</table>
</div>
)
}

First step will be declare a state variable as an array
state = { data : [] }
set your received data into data state
this.setState({
data : response.data
})
Then you can access your state data like this.state.data
render(){
const { data } = this.state
return (
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Mobile</th>
<th>Photo</th>
</tr>
{data && data.map(rowData => (
<tr key={rowData.id}>
<td>{rowData.id}</td>
<td>{rowData.name}</td>
<td>{rowData.mobile}</td>
<td>{rowData.photo}</td>
</tr>
)}
</table>
)
}
full example code click here

Related

Calling child API in React JS

I am trying to call API and display the data on table in react js. The API structure is like:
"items" : [ {
"#id" : "http://ABCD......" ,
"dateTime" : "2022-05-28T00:00:00Z" ,
"measure" : "http://measurement_1/abc" ,
"value" : 0.066
}
, {
"#id" : "http://ABCD......" ,
"dateTime" : "2022-05-28T00:15:00Z" ,
"measure" : "http://measurement_2/abc" ,
"value" : 0.066
}
, {
"#id" : "http://ABCD......" ,
"dateTime" : "2022-05-28T00:45:00Z" ,
"measure" : "http://measurement_3/abc" ,
"value" : 0.066
}
]
I was able to display 3 columns 'dateTime','measure','value' using following code.
class App extends React.Component{
state ={
items:[]
};
async componentDidMount(){
const response = await fetch('/L1931/readings?today');
const body = await response.json();
this.setState({items:body.items});
}
render(){
const {items} = this.state;
const itemList = items.map(item => {
return <tr key={item.dateTime}>
<td style={{whiteSpace: 'nowrap'}}>{item.dateTime}</td>
<td>{item.value}</td>
<td>{item.measure}</td>
</tr>
});
return (
<div>
<Table className="mt-4">
<thead>
<tr>
<th width="30%">Date</th>
<th width="30%">Value</th>
<th width="40%">Measurement</th>
</tr>
</thead>
<tbody>
{itemList}
</tbody>
</Table>
</div>
);
}
}
The output is like
Now, I want to call the child API under 'Measurement' column and display a certain column in the table. Can anybody help me to achieve this?
You can use Promise.all() for that use case. The following example will call all the measure URLs and then replace each measure field with API response.
async componentDidMount() {
const response = await fetch("/L1931/readings?today");
const body = await response.json();
Promise.all(
body.items.map(async (item) => {
const res = await fetch(item.measure);
const data = await res.json();
return { ...item, measure: JSON.stringify(data) };
})
).then((newItems) => {
this.setState({ items: newItems });
});
}
You can change the return { ...item, measure: JSON.stringify(data) } depending on the format you want.
Working Demo

React convert timestamp to date time inside ".map" function

I am building a table that fetches data from a json API. The API gives measurments on electricity power flow between diffrent countries, example:
GetFlow.json
[
{
"OutAreaElspotId": "DE",
"InAreaElspotId": "SE4",
"Value": -615,
"MeasureDate": 1646123700000
},
{
"OutAreaElspotId": "DK1",
"InAreaElspotId": "DE",
"Value": 1211.7925,
"MeasureDate": 1646123700000
},
{
"OutAreaElspotId": "DK1",
"InAreaElspotId": "NL",
"Value": 699.8785,
"MeasureDate": 1646123700000
}
]
I have managed to display the data in a HTML table:
My problem is that the Measure Date field is in seconds and not a real date and time. It is impossible for the usewr of the table to know what it means..
My code is as following:
PhysicalFlow.js
import React from 'react';
import axios from 'axios';
export default class PhysicalFlow extends React.Component {
state = {
flows: []
}
componentDidMount() {
let config = {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
}
}
let data = {
'HTTP_CONTENT_LANGUAGE': 'no',
}
axios.get('http://localhost:8010/proxy/restapi/PhysicalFlowMap/GetFlow', data, config)
.then(res => {
const flows = res.data;
this.setState({ flows });
})
};
render() {
return (
<table className="hor-zebra">
<thead>
<tr>
<th>
<span>Area</span>
</th>
<th>
<span>To</span>
</th>
<th>
<span>Measure Date</span>
</th>
<th>
<span>Value</span>
</th>
</tr>
</thead>
<tbody>
{
this.state.flows
.map(flow =>
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{flow.MeasureDate}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}
</tbody>
</table>
)
};
};
Now I have found the following code for converting data:
var t = new Date();
t.setSeconds( 1370001284 );
var formatted = moment(t).format("dd.mm.yyyy hh:MM:ss");
But I am unsure where I can place that code. I tried to put it into the .map function like this but it failed:
{
this.state.flows
.map(flow =>
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}
That's correct. You just missed the brackets and the return statement.
this.state.flows
.map(flow => {
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
return (
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
);
}
)
Refer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#comparing_traditional_functions_to_arrow_functions
I suppose you forgot to add a block inside map, so you can do more stuff in it:
this.state.flows.map((flow) => {
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
return (
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}

Can't fill my state in componentDidMound function

inside of my componentDidMount method I'm trying to make array of objects by using fetch. In my head it looks like this - on state I keep variable "loading" (true by default), and when my method is done with fetching it set it to false. On render method I've put if statement. But in real life my method filled array doesn't get executed (first console.log gets executed, second is not), . I'm losing my mind with this.
import { Company } from "../company/company.component";
export class CompanyList extends Component {
constructor(props) {
super(props);
this.state = {
tempResult: 10,
newArray: [],
loading: true,
};
}
componentDidMount = () => {
console.log(this.state.loading,"1");
const filledArray = this.props.companies.map((item) => {
fetch(`xxxx/incomes/${item.id}`)
.then((response) => response.json())
.then((data) => {
let transactionsToFloat = data.incomes.map((item) =>
parseFloat(item.value)
);
let result = transactionsToFloat.reduce((acc, num) => {
return acc + num;
}, 0);
result = Math.round(result * 100) / 100;
this.setState({ tempResult: result, loading: false });
console.log(item.id, item.name, item.city, result);
return {
id: item.id,
name: item.name,
city: item.city,
totalIncome: result,
};
});
this.setState({ loading: false });
return true;
});
this.setState({ newArray: filledArray });
};
render() {
if (this.state.loading) {
return <h1>Loading...</h1>;
} else if (!this.state.loading) {
return (
<div>
{/* <button onClick={this.handleClick}>Button</button> */}
<table>
<thead>
<tr>
<th> Id </th>
<th> Name </th>
<th> City </th>
<th> Total income </th>
</tr>
</thead>
{this.state.newArray.map((item) => (
<Company key={item.id} company={item} />
))}
</table>
</div>
);
}
}
}
Cheers
fetch is async, when you do this.setState({ loading: false }) after fetch, this line of code will be executed right away, before promise is even resolved. you are also not returning the data, but true values instead.
given that you are executing an array of promises, you may consider return fetch promises and wrap your array of promises with a Promise.all:
Promise.all(this.props.companies.map((item) => { return fetch().then().then() })
.then(results => this.setState({ newArray: results, loading: false }))
.catch(error => ... handle error here)
there is a caveat that Promise.all will reject if one of the promises fails. if you dont want that behavior you could use Promise.allSettled instead. allSettled will never reject and it returns instead an array of objects, with status and value keys.

for my code iam not getting pagenation and searchbar in reactjs

//here is my code//
class TableList extends Component {
constructor(props) {
super(props);
//var totalPages = 100 / 10; // 10 page numbers
this.state = {
query: "",
countries: [],
searchString:[],
currentPageNumber: 1,
pageOfItems: [],
totalItems: 4,
itemsPerPage: 10
}
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageOfItems) {
this.setState({ pageOfItems: pageOfItems });
}
handleInputChange = (event) => {
this.setState({
query: event.target.value
},()=>{
this.filterArray();
})
}
handleSelect(number) {
console.log('handle select', number);
this.setState({currentPageNumber: number});
}
componentDidMount() {
const apiUrl = 'https://indian-cities-api-nocbegfhqg.now.sh/cities';
fetch(apiUrl)
.then(res => res.json())
.then(
(result) => {
this.setState({
countries: result,
searchString:result,
currentPageNumber:result.currentPageNumber,
totalItems: result.totalItems,
itemsPerPage: result.itemsPerPage
});
},
)
}
filterArray = () => {
let searchString = this.state.query;
let result = this.state.countries;
if(searchString.length > 0){
result = result.filter(searchString);
this.setState({
result
})
}
}
render() {
const { countries} = this.state;
let totalPages = Math.ceil(this.state.totalItems / this.state.numItemsPerPage);
return(
<div>
<div className="container">
</div>
<h2>countrie List</h2>
<form>
<input type="text" id="filter" placeholder="Search for..." onChange={this.handleInputChange}/>
</form>
<Table>
<Pagination
bsSize="medium"
items={totalPages}
activePage={this.state.currentPageNumber} onSelect={this.handleSelect.bind(this)}/>
<thead>
<tr>
<th>#ID</th>
<th>countrie Name</th>
<th>Code</th>
<th>States</th>
</tr>
</thead>
<tbody>
{countries.map(countrie => (
<tr key={countrie.City}>
<td>{countrie.sno}</td>
<td>{countrie.City}</td>
<td>{countrie.State}</td>
<td>{countrie.District}</td>
</tr>
))}
</tbody>
</Table>
</div>
)
}
}
export default TableList;
//the error coming is
Warning: Encountered two children with the same key, `Wadi`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version
IN SHORT:
Search - filtered data stored in this.state.result - not used in render
this.setState({
result
})
as { result } is a short of { result: result } and this is good ... overwriting this.state.countries would result in source data loss (needs refetching)
render gets/make use of this.state.countries - always full dataset, not filtered by search, not divided by page ranges
You need to copy some data into this.state.result after fetching (not copy a countries reference)
Pagination - 'results' (not proper as above) records not subselected by range based on currentPage
Inspect state changes (check if properly working) in browser using react dev tools.

One data from two get method

I have two separate axios get method which map response data to separate data object. Then I map the data in render. I want to put data from both axios in to one object to map only one object in render. How could i do that?
One of two get function
getData() {
axios
.get("http://localhost/GetAll?", {
params: { rok: this.state.rok, idUchwaly: "1" },
headers: { Authorization: "Bearer " + this.state.token }
})
.then(response =>
response.data.map(data2 => ({
IDA: `${data2.idZadania}`,
idWersji: `${data2.idWersji}`,
Dzial: `${data2.dzial}`
}))
)
.then(data2 => {
if (data2 == "") {
} else {
this.setState({ data2, isLoadingdane: true });
}
})
.catch(error => this.setState({ error }));
}
Then I map data into a table
{this.state.isLoadingdane ? (
data2.map(user2 => {
const { IDA, idWersji, Dział } = user2;
return (
<tr id={IDA}>
<td>
<p>{idWersji}</p>
</td>
<td>
<p>{Dzial}</p>
</td>
</tr>
);
})
) : (
<tr>
<td colSpan="3">
<center>
<p>Brak</p>
</center>
</td>
</tr>
)}
I want one table in which i could put values from both get function
something like this: {value from getData}{value from getData2}
Instead of putting the response to the axios request in state directly, you could return the promise and wait for both of the requests to finish with Promise.all and then merge the objects in both arrays into one array.
Example
class App extends React.Component {
componentDidMount() {
Promise.all([this.getData(), this.getData2]).then(([data1, data2]) => {
this.setState({
data2: data1.map((item, index) => ({ ...item, ...data2[index] })),
isLoadingdane: true
});
});
}
getData = () => {
return axios
.get("http://localhost/GetAll?", {
params: { rok: this.state.rok, idUchwaly: "1" },
headers: { Authorization: "Bearer " + this.state.token }
})
.then(response =>
response.data.map(data2 => ({
IDA: `${data2.idZadania}`,
idWersji: `${data2.idWersji}`,
Dzial: `${data2.dzial}`
}))
);
};
getData2 = () => {
return axios.get(/* ... */);
// ...
};
render() {
// ...
}
}
Bartek, you need to map results like that:
const first = [{
x: 'x',
y: 'y',
}];
const second = [{
x: 'x',
z: 'z',
}];
const all = first.map(o => ({ ...o, ...second.find(f => f.x === o.x)}));
console.log(all);

Resources