Guys i know this already asked many times, but i still don't get how to solve my problem. So what i want to do is display some nested JSON data to HTML table.
So this is the JSON i fetch.
and this is my reactjs code:
var [infectionData, setInfectionData] = useState({
response: []
});
var [isLoaded, setLoaded] = useState(false);
useEffect(() => {
var fetchData = async () => {
var url = "https://api.covid19api.com/summary";
var result = await axios.get(url);
var response = result.data
response = Array(response);
setInfectionData({ response: response });
console.log(infectionData.response);
}
fetchData();
setLoaded(true);
});
and this is the HTML table:
<Table bordered hover className="mt-3 w-75">
<thead>
<tr>
<th>Country</th>
<th>Total Infection</th>
<th>New Deaths</th>
</tr>
</thead>
<tbody>
{
infectionData.response.Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))
}
</tbody>
</Table>
Any idea how to solve this ?
Here are the Array constructor https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Array
response = Array(response); remove this line and everything will be good.
Or
infectionData.response[0].Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))
You may try with this
infectionData.response.Countries && infectionData.response[0].Countries.map((item) => (
<tr>
<td>{item.Country}</td>
<td>{item.TotalConfirmed}</td>
<td>{item.NewDeaths}</td>
</tr>
))
Related
I need help rendering the table headers and the parsed information from an API only when the button is pressed. Along with refreshing the page when a different button is pressed so the array of 100+ objects don't stack on top of each other. I am using React to write this code. There is more to this code but this is a snippet and I want to apply it to the other buttons (3).
I'm also thinking of creating a new file for each API call to get their information and then importing them into this file to be enacted when the button gets pressed.
import { useState } from 'react';
export default function Markets() {
const API_KEY = process.env.REACT_APP_MS_API_KEY;
const [dataEndOfDay, setEndOfDay] = useState('');
async function getEndOfDay() {
try {
const response = await axios.get(
`${BASE_URL}eod?access_key=${API_KEY}&symbols=AAPL`
);
console.log(response.data.data);
setEndOfDay(
response.data.data.map((row) => {
return (
<tr>
<td>{row.date}</td>
<td>{row.symbol}</td>
<td>${row.open}</td>
<td>${row.close}</td>
</tr>
);
})
);
} catch (error) {
console.error(error);
}
}
return (
<div className="market-button">
<button onClick={getEndOfDay}>Get End of Day Report</button>
<table>
<tr>
<th>Date</th>
<th>Symbol</th>
<th>Open</th>
<th>Close</th>
</tr>
{dataEndOfDay}
</table>
}
You just need to wrap your table inside of an if statement. But also remove the empty string from your state and just leave it empty or set it to null.
const [dataEndOfDay, setEndOfDay] = useState();
return (
<div className="market-button">
<button onClick={getEndOfDay}>Get End of Day Report</button>
{ dataEndOfDay &&
<table>
<tr>
<th>Date</th>
<th>Symbol</th>
<th>Open</th>
<th>Close</th>
</tr>
{dataEndOfDay}
</table>
}
<div>
)
But on another note your code isn't the best for performance and I would recommend refactoring it. You shouldn't save the html data for your rows in state but rather just the data from the api and then just loop over it in the render.
import { useState } from 'react';
export default function Markets() {
const API_KEY = process.env.REACT_APP_MS_API_KEY;
const [dataEndOfDay, setEndOfDay] = useState();
async function getEndOfDay() {
try {
const response = await axios.get(`${BASE_URL}eod?access_key=${API_KEY}&symbols=AAPL`);
console.log(response.data.data);
setEndOfDay(response.data.data);
} catch (error) {
console.error(error);
}
}
return (
<div className="market-button">
<button onClick={getEndOfDay}>Get End of Day Report</button>
{
dataEndOfDay &&
<table>
<tr>
<th>Date</th>
<th>Symbol</th>
<th>Open</th>
<th>Close</th>
</tr>
{
dataEndOfDay.map(row => {
return (
<tr>
<td>{row.date}</td>
<td>{row.symbol}</td>
<td>${row.open}</td>
<td>${row.close}</td>
</tr>
);
}
}
</table>
}
</div>
);
}
Data is an array object. I want to render table columns dynamically according to data object. I used this same technique to generate table head its working. Is there any way to fix this issue?
const DataTable = ({data, deleteHandler, loading, tableFields}) => {
const thead = [];
const tbody = [];
const [values, setValues] = useState({});
for (const [key, value] of Object.entries(tableFields)) {
thead.push(<td>{value}</td>);
}
data.map((field) => {
for(const[key,value] of Object.entries(field)){
tbody.push(
<tr>
<td>{value}</td>
</tr>
);
}
})
return (
<Fragment>
<Card className={classes.__bk_admin_card}>
<Table borderless hover className={classes.__bk_admin_table}>
<thead>
<tr>
{thead}
</tr>
</thead>
<tbody>
{tbody}
</tbody>
</Table>
</Card>
</Fragment>
)
}
I am trying to read Database Data into a Table but I am getting an empty table from my Output though I am convinced I am doing the right thing.
Below is My code in the useEffect Hook and how I am Calling the data in the Table data jsx element.
Intervening for your Help
My Use useEffect Code
useEffect(() => {
const readCustomersData= async() =>{
const data = await getDocs(customersCollectionRef);
setCustomers(data.docs.map((doc) => ({ ...doc.data(), id:doc.id})));
}
readCustomersData();
},[])
How I am Calling The code in The jsx Elememnt
{ customers.map(( value, index) => {
return(
<tr key={index.id}>
<th scope="row">{index+1}</th>
<td>{value.cname}</td>
<td>{value.contact}</td>
<td>{}</td>
<th>{}</th>
<td>{}</td>
<td>{}</td>
<td>{}</td>
<td>{}</td>
<td className='p-2 d-flex justify-content-space-between'>
<Button variant='success'>Update</Button> <Button variant='danger'>Delete</Button>
</td>
</tr>
)
})}
</tbody>
I am having an issue mapping some JSON:
https://environment.data.gov.uk/flood-monitoring/id/floodAreas/?county=Lincolnshire
Would really appreciate the help, thanks
I am using the following code to attempt to map the json object
await fetch('https://environment.data.gov.uk/flood-monitoring/id/floodAreas/?county=Lincolnshire')
.then(res => res.json())
.then(json => {
this.setState({
hasLoaded: true,
weatherItems: json
})
});
static renderFloodTable(weatherItems) {
return (
<table class="centerTable" className='table table-striped' aria-labelledby="tabelLabel">
<thead>
<tr>
<th>County. (C)</th>
</tr>
</thead>
<tbody>
{weatherItems.items.map(item =>
<tr key={item.fwdCode}>
<td>{item.fwdCode}</td>
</tr>
)}
</tbody>
</table>
);
}
i think the rendering in calling too soon so the weatherItems is'nt set yet. try this:
{weatherItems ? weatherItems.items.map( // ... etc... // ) : null}
and btw, you should not use await And .then toogether... choose one...
I want to populate an array before render, and the render is conditional based on the length of the array.
If the length of the array > 0, do the render, otherwise don't.
But it seems that the length is always 0 becasue useEffect is asynchronous, so the render is never done.
Below is my code:
function OrderDetail(props) {
const {userInfo} = useSelector(state => state.user)
const [order, setOrder] = useState({});
const [items, setItems] = useState([]);
useEffect(()=>{
if(!userInfo){
props.history.push("/")
return
}
const fetchOrderAndItems = async () => {
// Get an order from backend.
const order = await axios.get("/api/orders/" + props.match.params.id, {
headers:{
authorization: "Bearer " + userInfo.token
}
});
const order_data = order.data
setOrder(order_data)
// Take out the id of all items in the order, retrieve each product from backend,
//push them in "items_array" and set it in the "items" state.
let items_array = [];
order_data.orderItems.forEach( async (orderItem) => {
const {data} = await axios.get("/api/products/" + orderItem.productId);
items_array.push(data);
})
console.log("items_array.length: " + items_array.length);
console.log(items_array);
setItems(items_array);
}
fetchOrderAndItems();
}, [userInfo]);
// For each item in the "items" state, return a <tr> element.
const itemsHtml = items.map(item => {
return <tr key={item._id}>
Something to display.
</tr>
})
// if itemsHtml.length > 0, render {itemsHtml}, otherwise display "Your cart is empty.".
// But what is displayed is always "Your cart is empty."
return <table className="table text-center">
<thead style={{border: "none"}}>
<tr>
<th style={{border: "none"}} scope="col"></th>
<th style={{border: "none"}} scope="col">Name</th>
<th style={{border: "none"}} scope="col">Price</th>
<th style={{border: "none"}} scope="col">Qty</th>
<th style={{border: "none"}} scope="col">Subtotal</th>
<th style={{border: "none"}} scope="col"></th>
</tr>
</thead>
{
itemsHtml.length > 0?
<tbody>
{itemsHtml}
</tbody>
:
<tbody>
<tr className="text-center">
<th className="text-center" scope="row" colSpan="6">Your cart is empty. </th>
</tr>
</tbody>
}
</table>
The output of the 2 lines of "console.log" is:
We can see that the length of items_array is 0 while there is content in it, and I think it is because it is asynchronous.
And I guess because the length is 0, so the conditional render of itemsHtml.length > 0? is never true, so the desired content is never rendered.
Could anyone teach me how to solve it?
Thanks
Instead of for-each'ing over the items you should map the item ids to an array of GET requests and Promise.all them. The forEach doesn't wait for the callbacks to complete, this is why the array is empty when you log it but become populated by the time the log is displayed.
Promise.all will wait for all mapped requests to resolve before it resolves with an array of resolved item values.
Promise.all(
order_data.orderItems.map(
({ productId }) => axios.get(`/api/products/${productId}`)
))
.then(results => setItems(results));