React data isn't being displayed - reactjs

I'm trying to display these data that is stored in countries list, however, it is result in me getting nothing in my Table. The problem is most likely caused by the Table not rerendering correctly, I tried to use useEffect on line 14 to print out the length of the list, and I did get the correct result. Any hint would be appreciated!
import React, { useState, useEffect } from "react";
import getData from "../Hooks/getData";
import Table from "react-bootstrap/Table";
const Lists = () => {
const [countries, setCountries] = useState([]);
if (countries.length === 0) {
getData().then((data) => {
setCountries(data.data.Countries);
});
}
useEffect(() => {
console.log(countries.length);
});
const getInfo = () => {
countries.map((country) => {
return (
<tr>
<td>{country.Country}</td>
<td>{country.NewConfirmed}</td>
<td>{country.TotalConfirmed}</td>
</tr>
);
});
};
return (
<Table striped bordered hover>
<thead>
<tr>
<th>Country Name</th>
<th>New Confirmed</th>
<th>Total Confirmed</th>
</tr>
</thead>
<tbody>{getInfo()}</tbody>
</Table>
);
};
export default Lists;

Your getInfo does not return anything.
Either use the implicit return, by not using {} around the funtion body, or explicitly use the return statement
const getInfo = () => countries.map((country) => {
return (
<tr>
<td>{country.Country}</td>
<td>{country.NewConfirmed}</td>
<td>{country.TotalConfirmed}</td>
</tr>
);
});
or
const getInfo = () => {
return countries.map((country) => {
return (
<tr>
<td>{country.Country}</td>
<td>{country.NewConfirmed}</td>
<td>{country.TotalConfirmed}</td>
</tr>
);
});
};

Related

Why when I map a fetched array with ReactJs it only displays one result, when it brings all the results?

I'm fetching data from an endpoint, and if I use a console.log(data) it shows it correctly.
Image of my array
I only want data.data, so I use console.log(data.data) and apparently It show correctly what I need.
Data that I need
My problem is that I'm trying to show all clients in a table, but it only shows one of them.
This is my code:
import { useEffect, useState } from "react";
function Activity() {
function LoadActivity() {
fetch("https://localhost:7079/client/listClient")
.then((response) => {
return response.json()
})
.then((data) => {
setActivity([data.data])
});
}
const [actividad, setActivity] = useState([]);
useEffect(() => {
LoadActivity();
}, []);
return (
<div>
<h1>Cliente</h1>
<table>
<thead>
<tr>
<th>Id</th>
<th>name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{
actividad.map((client, i )=>(
<tr key={client[i].id}>
<td>{client[i].name}</td>
<td>{client[i].Email}</td>
<td>{client[i].id}</td>
</tr>
))
}
</tbody>
</table>
</div>
);
}
export default Activity;
And this is how it displays:
What is displayed
I tried to do it like this question 3 years ago.
I'm very new with React, and I don't know what I'm missing.
This is how I resolved it
const [equipo, setEquipo] = useState([]);
useEffect(() => {
obtenerDatos();
}, []);
const obtenerDatos = async () =>{
const datos = await fetch('https://localhost:7079/cliente/listarClientes')
const clientes = await datos.json()
setEquipo(clientes.data)
}

use useMemo for large tables in react without react-table

I have a table that has a big database, 2k lines +
So I had a function to filter and organize this working, but it takes 1-2 secs to filter, is it possible to do with useMemo or useCallBack since I always need to redo the database?
export default function Table(props) {
const [order, setOrder] = useState(true);
function handleHeaderClick(clickedHeader) {
setOrder(!order);
const newdata = props.data.sort((a, b) => {
const x = a[clickedHeader];
const y = b[clickedHeader];
if (order && x > y) return -1;
return 1;
});
props.setdata(newdata);
}
function createHeader(header, index) {
if (header.includes("BET") || header.includes("C") || header.includes("CHECK")) {
return (
<th onClick={(e) => handleHeaderClick(header)} key={index}>
{header}
</th>
);
}
}
function createRow(row) {
// ♠♥♦♣
try {
return row.replace(/s/g, "♠").replace(/d/g, "♦").replace(/c/g, "♣");
} catch (e) {
return row;
}
}
function tableRow(row, indexRow) {
return (
<tr key={indexRow}>
{Object.keys(row).map((hd) => {
const value = createRow(props.data[indexRow][hd]);
if (hd.includes("BET") || hd.includes("C") || hd.includes("CHECK")) {
return (
<td className={value[1]} key={hd}>
{value}
</td>
);
}
})}
</tr>
);
}
return (
<table>
<thead>
<tr>{Object.keys(props.data[0]).map((header, indexHeader) => createHeader(header, indexHeader))}</tr>
</thead>
<tbody>{props.data.map((row, indexRow) => tableRow(row, indexRow))}</tbody>
</table>
);
}
I think I have to change something in my handleHeaderClick function, I have already tried some solutions of this type
const test = useMemo(() => handleHeaderClick, [props.data]);
but my code stops working
where's my table
#edit violation on chrome
[Violation] 'setTimeout' handler took 1458ms
#edit2
On firefox works correct

Log one field from each element of an array

I have objects, in the database. I want to grab the userId using axios, but when I tried to console.log() it. It shows undefined. hen I hardcoded it and targeted it by array, it shows.
How can I console log all of userId? I would like to grab it so I can use it as an endpoint for my database
const res = await userRequest.get('user/find/'+userId)
I want to grab the userId only.
import React, { useEffect, useState } from 'react'
import { format } from 'timeago.js'
import { userRequest } from '../../requestMethod'
import './Widgetlg.css'
const WidgetLg = () => {
const Button = ({ type }) => {
return <button className={'widgetLgButton ' + type}>{type}</button>
}
const [orders, setOrders] = useState([])
const [users, setUsers] = useState([])
useEffect(() => {
const getOrders = async () => {
//this is just a shorcut api
try {
const res = await userRequest.get('orders')
setOrders(res.data)
console.log(res.data?.userId)
console.log(res.data)
console.log(res.data[0].userId)
} catch (error) {
console.log(error)
}
}
getOrders()
}, [])
useEffect(() => {
const getUsername = async () => {
try {
const res = await userRequest.get('user/find/')
setUsers(res.data)
} catch (error) {}
}
getUsername()
}, [])
return (
<div className="widgetLg">
<h3 className="widgetLgTitle">Latest Transactions</h3>
<table className="widgetTable">
<tr className="widgetLgTr">
<th className="widgetLgTh">Customer</th>
<th className="widgetLgTh">Date</th>
<th className="widgetLgTh">Amount</th>
<th className="widgetLgTh">Status</th>
</tr>
{orders.map((order) => (
<tr className="widgetLgTr">
<td className="widgetLgUser">
<span className="WidgetLgName"> **I want here to show the username** </span>
</td>
<td className="widgetLgDate"> {format(order.createdAt)} </td>
<td className="widgetLgAmmount">P {order.amount} </td>
<td className="widgetLgStatus">
<Button type={order.status} />
</td>
</tr>
))}
</table>
</div>
)
}
export default WidgetLg
You could try something like this if I understand you correctly
const userIdsArray = res.data.map(d => d.userId);
console.log(userIdsArray);
res.data is an array. To log all elements, you could just iterate over them:
res.data.forEach(el => console.log(el.userId));
The reason that console.log(res.data) gives undefined is that the array itself doesn't have a userId field, only the elements of the array do.

React toggle "Show All" and "Show Winners" doesn't work

I have been struggling on this piece of codes which I suppose a button's clicked, the table will toggle between show all items and show winner items only.
Problem: The button has to be clicked two times to show winner items. Can't revert back to show all.
Do appreciate if someone can help. Thank you so much.
const MovieList = () => {
// Get Movies
const [movies, setMovies] = useState([])
const [winner, filterWinner] = useState(false)
const fetchMovies = async () => {
const res = await fetch('http://localhost:5000/data')
const data = await res.json()
return data
}
useEffect(() => {
const getMovies = async () => {
const moviesFromServer = await fetchMovies()
setMovies(moviesFromServer)
}
getMovies()
}, [])
//toggle between setting movies to all movies and winner movies.
//movie is an object that has a key and value pair "winner" : "True" or "winner" : "False"
const toggleWinner = () => {
filterWinner(!winner)
if (winner === true) {
const winners = movies.filter((movie) => movie.winner === 'True');
setMovies(winners);
} else {
setMovies(movies);
}
}
return (
<div className="container">
<h1>Movies</h1>
<hr />
<div>
<Button onClick={toggleWinner} color="info">{winner ? "Show All" : "Show Winners"}</Button>
</div>
<div>
<table className="table table-bordered table-striped">
<thead className="thead-dark">
<tr>
<th>Year</th>
<th>Film Name</th>
<th>Oscar Winner</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{movies.map(movie => (
<tr key={movie.id}>
<td>{movie.year}</td>
<td>{movie.filmName}</td>
<td>{movie.winner}</td>
<td>{movie.country}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)
}
export default MovieList;
The problem here is when you set state, that state will not be updated immediately, so you can't compare winner to true.
You can try this approach
const toggleWinner = () => {
//winner = false
filterWinner(prev => {
if(!prev) { // winner = true
const winners = movies.filter((movie) => movie.winner === "True");
setMovies(winners);
}
else {
setMovies(movies);
}
return !prev
});
};
Another problem is that you mutated the movies, so when you toggle again, old movies value is gone.
Check this codesandbox to see how I fixed that: https://codesandbox.io/s/frosty-browser-o8jeb?file=/src/App.js
If your state change depends on previous state value you need to call a function inside your update function.
const [state,setState]=useState(false);
If you want to toggle the state value you need to call update function like this.
setState(state=>!state)
In your case
filterWinner(winner=>!winner)
Note: you can use any name you want as argument inside update function.

Removing Item from DOM display (React)

sample image of page so far
Please see the above image. I'm wanting to be able to remove the string in the "skill" column when it is deleted after clicking the "Delete" button on the right. I can delete an Employee using filter() with the Delete button on the left. This removes the entire row from the DOM, which is great, but I would like the Delete button on the right to simply remove the content from the Skill(s) column for that particular employee.
I have tried doing something similar in the deleteSkill() function, but I am not sure how to remove the content of the Skill(s) column without deleting the entire row. The issue lies in my setList() function within my deleteSkill() function. Any ideas would be greatly appreciated.
Here is the code:
import React, { Fragment, useEffect, useState } from 'react';
const List = () => {
const [list, setList] = useState([]);
//DELETE Employee by ID
const deleteEmployee = async (id) => {
try {
const deleteEmployee = await fetch(`http://localhost:5000/employees/${id}`, {
method: "DELETE"
});
setList(list.filter(item => item.employee_uuid !== id));
} catch (err) {
console.error(err.message)
}
};
//DELETE Skill by ID
const deleteSkill = async (id) => {
try {
const deleteSkill = await fetch(`http://localhost:5000/employees/${id}/skills`, {
method: "DELETE"
});
setList(list.filter(item => item.summary !== id));
} catch (err) {
console.error(err.message)
}
};
const getList = async () => {
try {
const response = await fetch("http://localhost:5000/employees")
const jsonData = await response.json();
setList(jsonData);
} catch (err) {
console.error(err.message);
}
};
useEffect(() => {
getList();
}, []);
console.log(list);
return (
<Fragment>
{" "}
<h1 class="text-center">Employee Skills Tracker</h1>
<table class="table mt-5 text-center">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th></th>
<th></th>
<th>Skill(s)</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{list.map(item => (
<tr key={item.employee_uuid}>
<td>{item.firstname}</td>
<td>{item.lastname}</td>
<td>Edit</td>
<td><button className="btn btn-danger" onClick={() => deleteEmployee(item.employee_uuid)}>Delete</button></td>
<td>{item.summary}</td>
<td>Edit</td>
<td><button className="btn btn-danger" onClick={() => deleteSkill(item.employee_uuid)} >Delete</button></td>
</tr>
))}
</tbody>
</table>
</Fragment>
);
};
export default List;
Instead of using list.filter(), use list.map(). The key is that you want to return a 1:1 list of modified elements, not a list without certain elements.
If you want to remove the summary for just a specific employee, I'd recommend
setList(list.map(item => {
if (item.id !== id) {
return item; // not the right employee, pass it through
}
let newItem = {...item};
delete newItem.summary;
return newItem;
}));
It's more complex, because you have to explicitly return what you want, but it's also what you're asking for.

Resources