I'm trying to make a shopping cart table in which it shows an image, name of the product and a remove button. I've the id of each product from the localStorage and call all the data of that id with Axios.get(by id).
I'd created a table to show the price, image and name of the product, but my .map function don't show the info in the website (even though I can see it with a console.log). Here is the code:
import Axios from "axios";
import React from "react";
function ClientCardBlock() {
let memory = window.JSON.parse(localStorage.getItem("toy"));
console.log(memory); **this log shows me that all the IDs are now in an array**
const renderItems = () => {
memory.map(
async (toy_id) =>
await Axios.get(`http://************/${toy_id}`).then(
(response) => {
const toy = response.data;
console.log(toy.price); **this log show me the price of each toy, so it's working**
return (
<tr key={toy._id}>
<th>
<img
alt=""
className="card-img-top embed-responsive-item"
src={`http://*********/${toy.images}`}
/>
</th>
<th>$ {toy.price}</th>
<th>
<button>Remove</button>
</th>
</tr>
);
}
)
);
};
return (
<div>
<table className="table table-bordered">
<thead>
<tr>
<th scope="col">Image product</th>
<th scope="col">Product</th>
<th scope="col">Remove</th>
</tr>
</thead>
<thead>{renderItems()}</thead>
</table>
</div>
);
}
export default ClientCardBlock;
Normally you'd be able to just change it so that renderItems is a functional component.
function RenderItems() {
return memory.map...(etc)
}
...
<thead><RenderItems /></thead>
but since this is an async function, you need to use a useEffect. This useEffect gets the data and saves it into your component state. Then once it exists, it will render later. The key point is to seperate the fetching from the rendering.
function ClientCardBlock() {
const [data, setData] = useState([]);
useEffect(() => {
/* this runs on component mount */
const memory = window.JSON.parse(localStorage.getItem("toy"));
Promise.all(memory.map((toy_id) => Axios
.get(`http://************/${toy_id}`)
.then((response) => response.data)))
/* Wait on the Promise.All */
.then(newData => {
/* Set the data locally */
setData(newData);
});
}, []);
return (
<div>
<table className="table table-bordered">
<thead>
<tr>
<th scope="col">Image product</th>
<th scope="col">Product</th>
<th scope="col">Remove</th>
</tr>
</thead>
<thead>
{data.map(toy => (
<tr key={toy._id}>
<th>
<img
alt=""
className="card-img-top embed-responsive-item"
src={`http://*********/${toy.images}`}
/>
</th>
<th>$ {toy.price}</th>
<th>
<button>Remove</button>
</th>
</tr>
)}
</thead>
</table>
</div>
);
}
export default ClientCardBlock;
Related
import React from 'react'
import './user.css'
const User = ({ id, email, name, onDelete }) => {
const handleDelete = () => {
onDelete(id);
}
return (
<table className='table'>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>edit</th>
<th>delete</th>
</tr>
</thead>
<tbody>
<tr>
<td>{name}</td>
<td>{email}</td>
<td>
<button>edit</button>
<button onClick={handleDelete}>delete</button>
</td>
</tr>
</tbody>
</table>
)
}
export default User
You're creating a new table for every user. That's why your headers are duplicated. You only need a new row for every user instead of an entire table for each user.
I'd separate the UserTable and the UserRow.
// UserTable.jsx
import React from 'react'
import './user.css'
import './UserRow'
const UserTable = ({ users, onDelete }) => {
return (
<table className='table'>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>edit</th>
<th>delete</th>
</tr>
</thead>
<tbody>
{users.map(user => {
<UserRow key={user.id} userId={user.id} userName={user.name} email {user.email} onDelete={onDelete} />onDelete={onDelete} />
})
}
</tbody>
</table>
)
}
export default UserTable
// UserRow.jsx
import React from 'react'
import './user.css'
const UserRow = ({ userId, email, userName, onDelete }) => {
const handleDelete = () => {
onDelete(userId);
}
return (
<tr>
<td>{userName}</td>
<td>{email}</td>
<td>
<button>edit</button>
<button onClick={handleDelete}>delete</button>
</td>
</tr>
)
}
export default UserRow
All in all trying to loop over a jsonplaceholder's (/users) name, username, and email. Im getting the data with the help of axios and im displaying it through react. I have two seperate files: App.js (the one that comes with react) and AlbumList.js
In App.js:
import React, { Component } from 'react'
import './App.css';
import AlbumList from './Components/AlbumList';
class App extends Component {
render() {
return (
<div className="App">
<AlbumList/>
</div>
)
}
}
export default App
And in Album.List
import axios from 'axios';
import React from 'react';
export default class AlbumList extends React.Component {
state = {
persons: [],
};
componentDidMount() {
axios.get('https://jsonplaceholder.typicode.com/users').then(res => {
console.log(res);
this.setState({ persons: res.data });
});
}
render() {
return (
<div>
<table class="table">
<caption>List of users</caption>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">name</th>
<th scope="col">username</th>
<th scope="col">e-mail</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"></th>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
</tbody>
</table>
{/* { this.state.persons.map(person => <div>{person.name} | {person.username} | {person.email}</div> )} */}
</div>
)
}
}
The table im using is the one that bootstrap offers, the default one. How do I do this? thanks
You need to map the data you got from your fetch request to the "tbody" tag, here you are just mapping the result in a div.
Check below your code with the modification needed:
render() {
return (
<div>
<table class="table">
<caption>List of users</caption>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">name</th>
<th scope="col">username</th>
<th scope="col">e-mail</th>
</tr>
</thead>
<tbody>
{ this.state.persons.map(person =>
<tr>
<th scope="row"></th>
<td>{person.name}</td>
<td>{person.username}</td>
<td>{person.email}</td>
</tr> )}
</tbody>
</table>
</div>
)
}
Edit: typo
I am trying to hit an api available at covid19 api [ you can see directly , click it ] but I am not able to map through the state.
I tried browsing the questions and still didn't find it .
my code in app.js is
import React, { Component } from 'react'
import api from '../api/covidapi'
import SearchBar from './SearchBar'
class App extends Component {
constructor(props) {
super(props);
this.state = {
country : 'Please Enter the country',
active_cases : 'No country found',
countries : [],
errorMessage : '',
isLoading : false,
};
}
async componentDidMount() {
const response = await api.get('/summary');
console.log('data loaded = > ', response);
console.log(response.data.Countries.length) // giving 247
console.log('countries ', response.data.Countries) //lists all countries {....},{...}...
this.setState({countries:response.data.Countries})
// console.log('global end')
this.setState({
totalConfirmed : response.data.Global.TotalConfirmed,
})
} //component did mount ended.
onSearchSubmit = async (country) =>{
console.log(country)
try {
const response =
await api.get(`/live/country/${country}/status/confirmed`)
this.setState({country:country, active_cases:response.data[6].Active})
}
catch(e) {
this.setState({errorMessage : "Country Doesn't exist or misspelled"})
}
}; //onsearch submit ended.
render() {
return (
<div>
<div className="container">
<p style={{textAlign:'center',
backgroundColor:'green',
color:'white',
width:'97%',margin:'auto',
padding:'24px',
marginTop:'12px',}}>
Total confirmed as of now is <span> : </span>
<span style={{color : 'red'}} >
{this.state.totalConfirmed}
</span>
</p>
<SearchBar onSubmit = {this.onSearchSubmit}/>
</div>
<div className="container">
<h2 className="bg bg-primary" style={{marginBottom:'0px',
textAlign:'center',marginTop:'15px',
padding:'10px'}}>Covid19 Cases In single Country
</h2>
<table className="table table-striped">
<thead>
<tr>
<th>Country</th>
<th>Acitve Cases</th>
</tr>
</thead>
<tbody>
<tr>
<td>{this.state.country}</td>
<td>{ this.state.active_cases}</td>
</tr>
</tbody>
</table>
</div>
<br />
<hr />
<div className="container">
<div style={{textAlign:'center',color:'red',fontWeight:'bold'}}>
</div>
<h2 className="bg bg-primary" style={{marginBottom:'0px',
textAlign:'center', padding:'10px'}}>
Covid19 Cases Worldwide
</h2>
<table className="table table-striped table-hover table-dark">
<thead>
<tr>
<th>S.N</th>
<th>Country Name</th>
<th>Confirmed Cases</th>
<th> Total Deaths</th>
<th>Total Recovered</th>
</tr>
</thead>
<tbody>
{
Object.keys(this.state.countries).map((country) => (
<tr>
<td>{country}</td>
<td>........</td>
<td>........</td>
<td> ........</td>
<td>............</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
);
}
}
export default App;
and covidapi.js code is
import axios from 'axios'
export default axios.create({
baseURL :'https://api.covid19api.com'
})
The problem is in this section of the code in app.js
{
Object.keys(this.state.countries).map((country) => (
<tr>
<td>{country}</td>
<td>........</td>
<td>........</td>
<td> ........</td>
<td>............</td>
</tr>
))
}
I am not able to map through countries in my state , I think there is
problem with the Objects and array.
when Render the country that is passed in map it return the integer value like 1,2,3 .... and not able to get other values.
Response in the console looks like this
What I am trying is to display the all the countries list to the table whenever the application loads.
You can use this.state.countries directly without Object.keys() (It is an array already), and use the properties inside each item as follows:
{
this.state.contries.map(item => {
return(
<tr>
<td> { item.Country } </td>
<td> { item.totalConfirmed } </td>
... // Other tds
</tr>
)
}
}
There are quite a few answers that I found but none of them seem to work for my scenario.
I want to make each row clickable and log it on the console. How can I achieve this?
My React code is as follows:
class ConsumerList extends Component {
handleClick = building => {
console.log(building);
};
render() {
return (
<div className="table-responsive table-hover">
<table className="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Farm</th>
<th scope="col">Cost</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
{this.props.buildings.map(building => (
<tr key={building.id} onClick={() => this.handleClick(building)}>
<th scope="row">{building.id}</th>
<td>{building.name}</td>
<td>{building.farmName}</td>
<td>{building.cost}</td>
<td className="text-success">
<FontAwesomeIcon icon={faArrowDown} />
{building.change}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default ConsumerList;
onClick={(building) => this.handleClick(building)} modify this in your code while adding the listener. You will get the log into the console.
You need a routing setup.Use the withRouter high order component, and wrap that to the component that will push to history so that you get access to the history object, to perform various routing operations.
Check out the official documentation for more info
import React from "react";
import { withRouter } from "react-router-dom";
class ConsumerList extends React.Component {
handleClick = building => {
console.log(building);
this.props.history.push("/some/Path"); //path you want to redirect to
};
render() {
return (
<div className="table-responsive table-hover">
<table className="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Farm</th>
<th scope="col">Cost</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
{this.props.buildings.map(building => (
<tr key={building.id} onClick={(building) => this.handleClick(building)}>
<th scope="row">{building.id}</th>
<td>{building.name}</td>
<td>{building.farmName}</td>
<td>{building.cost}</td>
<td className="text-success">
<FontAwesomeIcon icon={faArrowDown} />
{building.change}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default withRouter(MyComponent);
I'm trying to display key-value pairs in react js,
but somehow I cannot display them properly. I have created a table widget and I am not getting the right display
My table Widget
import React from "react";
function Table(props) {
const { tablevalue } = props;
console.log(tablevalue);
return (
<div className="table">
<table className="table table-hover">
<tbody>
{tablevalue.map((item, value) =>
Object.entries(item, (key, value) => {
return (
<tr className="table-row">
<th scope="col" key={`tablevalue-${key}`}>
{key}
</th>
<td key={`tablevalue-${value}`}>{value}</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
);
}
export default Table;
app.js
import React, { Fragment } from "react";
import Dropdown from './components/widgets/Dropdown/index'
import Table from './components/widgets/Table/index'
function DropdownTest() {
return (
<h3>
<b>Profit</b>
</h3>
<br />
<Table
tablevalue = {[{key:'Binance' , value: 'Polonix'}, {key:'Profit' , value:'Loss'}]}
/>
</div>
);
}
export default DropdownTest;
My output
Whereas I want my output to be displayed in terms of table
You can use table header
<tbody>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
{tablevalue.map(({ key, value }) => (
<tr className="table-row">
<td key={`tablevalue-${key}`}>{key}</td>
<td key={`tablevalue-${value}`}>{value}</td>
</tr>
))}
</tbody>
Code
const Table = ({ tablevalue }) => (
<div className="table">
<table className="table table-hover">
<tbody>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
{tablevalue.map(({ key, value }) => (
<tr className="table-row">
<td key={`tablevalue-${key}`}>{key}</td>
<td key={`tablevalue-${value}`}>{value}</td>
</tr>
))}
</tbody>
</table>
</div>
);
const DropdownTest = () => (
<div>
<h3>
<b>Profit</b>
</h3>
<br />
<Table
tablevalue={[
{ key: "Binance", value: "Polonix" },
{ key: "Profit", value: "Loss" }
]}
/>
</div>
);
ReactDOM.render(
<React.StrictMode>
<DropdownTest />
</React.StrictMode>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I've not seen Object.entries used this way. I would usually use a forEach on it:
Object.entries(item).forEach(entry => {
let key = entry[0];
let value = entry[1];
});
Though a little bit more performant would be using a for in instead, as Object.entries creates a brand new array then forEach iterates through that, which is unnecessary:
for (const key in item) {
let value = obj[key];
}
You can do it this way:
import React from "react";
export default props => {
console.log(props.tablevalue);
const ths = props.tablevalue.map(({ key, value }) => (
<th key={value}>{key}</th>
));
const values = props.tablevalue.map(obj => <td>{obj.value}</td>);
return (
<>
<table>
<tr>{ths}</tr>
<tr>{values}</tr>
</table>
</>
);
};
Here's a stackblitz that displays the table.
Ultimately it all comes down to how you want that table to be displayed, you can tweak some things as you want.
I think you have to create a header separately. and after that loop thought the data and apply css for table row. please find the below code.
import React from 'react';
import './index.css';
function Table(props) {
const {
tablevalue,
} = props
console.log(tablevalue)
return (
<div className="table">
<table className="table table-hover">
<tbody>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
{tablevalue.map((item, value) => {
return (
<tr className="table-row">
<td key={`tablevalue-${value}`}>{item.key}</td>
<td key={`tablevalue-${value}`}>{item.value}</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
export default Table;
Check this sandbox: https://codesandbox.io/s/goofy-breeze-fdcdr
Object.keys(tablevalue[0]).map((key) => {key}). You can use this in header tr and loop over it then
Change the Table component to something like this:
import React from "react";
function Table(props) {
const { tablevalue } = props;
return (
<div className="table">
<table className="table table-hover">
<tbody>
<tr>
{Object.keys(tablevalue[0]).map(key => (
<th key={key}>{key}</th>
))}
</tr>
{tablevalue.map(({ key, value }) => (
<tr className="table-row" key={`tablevalue-${key}`}>
<td>{key}</td>
<td>{value}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Table;