React.js using onclick function to render a table - reactjs

I have an array of objects coming from two different api. the first api I am converting it to a bullet point using
tag. and the second api should be converted to a table using tag. What I want to do is whenever I click on the bullet point it should show the table with the appropriate data. I was successfully able to get the data from both apis.
The main problem I am having is, the onClick function. First, after mapping the bullet point, the onclick function treat it as one gigantic click button. they are not seperated. Second, when I tried to hard code it , since they are only 8 bullet points. I was not able to get the data on a table.
I start coding just about a month and half ago, I have been trying everything I know for the last five days. At this point I ran out of ideas.
note that this is an example of only the fisrt table i have 8 more.
Please Help me guys thank you!
import React, { useEffect, useState } from 'react';
import './App.css';
const App = () => {
const reqMenu = "fake link";
const reqDescription = "fake link";
const [recipes, setRecipes] = useState([]);
const [description, setDescription] = useState([])
useEffect(() => {
getReq()
getDesc()
},[]);
const getReq = async () => {
const response = await fetch(reqMenu);
const data = await response.json()
setRecipes(data)
// console.log(data)
};
const getDesc = async () => {
const response= await fetch(reqDescription);
const data = await response.json()
setDescription(data)
// console.log(data)
}
const ss = description.filter((e) => (e.short_name.startsWith("SS")))
return (
<div className="App">
<h1>Menu Categories</h1>
<div>
<ul>
{recipes.map((recipe ,id, index) => (
<li key={id} onClick={() =>
{if(index[0] = recipes[0]["short_name"]){
return <table>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
{ss.map((s) =>{
<tr key={id}>
<td>{s.name}</td>
<td>{s.description}</td>
</tr>
})}
</table>
}}}>
{recipe.name}-({recipe.short_name})
</li>
))}
</ul>
</div>
</div>
);
}
export default App;

onClick doesn't accept a return value. What you want to do is conditionally render the components based on state from the onClick.
.map also does not have an id argument.
Also, JavaScript comparison is done using == or ===. Using a single = will do assignment, not comparison.
const initialListState = recipes.map(() => false);
const [listState, setListState] = useState(initialListState);
return (
<div className="App">
<h1>Menu Categories</h1>
<div>
<ul>
{recipes.map((recipe, index) => (
<li
key={index}
onClick={() => {
const newListState = [...listState];
newListState[index] = true;
setListState(newListState);
}
>
<table>
<thead
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{listState[index] && (
ss.map((s, sindex) => (
<tr key={sindex}>
<td>{s.name}</td>
<td>{s.description}</td>
</tr>
)
}
</tbody>
</table>
{recipe.name}-({recipe.short_name})
</li>
}
</ul>
</div>
</div>
);

Related

reactjs error- TypeError: Cannot read property 'map' of undefined

import React , {useState, useEffect} from 'react'
import styles from './Statewise.css';
const Statewise = () => {
const [data, setData]=useState([]);
const getCData = async () => {
const res = await fetch('https://api.covid19india.org/data.json');
const actualData = await res.json();
console.log(actualData.Statewise);
setData(actualData.Statewise);
}
useEffect(() => {
getCData();
}, [])
return (
<div className="bts">
<div className="container-fluid mt-5">
<div className="main-heading">
<h1 className="mb-5">
<span className="font-weight-bold">INDIA COVID 19 TRACKER</span>
</h1>
</div>
<div className="table-responsive">
<table className="table table-hover">
<thead className="thead-dark">
<tr>
<th>States</th>
<td>Confirmed</td>
<td>recovered</td>
<td>death</td>
<td>active</td>
<td>updated</td>
</tr>
</thead>
<tbody>
{
data.map((curElem) => {
return(
<tr key={curElem.id}>
<th>{curElem.state}</th>
<td>{curElem.Confirmed}</td>
<td>{curElem.recovered}</td>
<td>{curElem.deaths}</td>
<td>{curElem.active}</td>
<td>{curElem.lastupdatedtime}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
</div>
</div>
)
}
export default Statewise;
Not able to extract values from the api.
I have tried data && data.map(... this is also not working.
I have tried adding the load and error methods but then also the main data from the api id not displayed.
please suggest solutions .
Your actualData does not contain Statewise field but it does contain statewise (See difference in s in both fields)
So to solve this just replace Statewise with statewise
const getCData = async () => {
const res = await fetch('https://api.covid19india.org/data.json');
const actualData = await res.json();
setData(actualData.statewise);
}
When you use data in you HTML you can make a conditional statement to be sure that your data are loaded.
For exemple :
{
data ? data.map((curElem) => {
return(
<tr key={curElem.id}>
<th>{curElem.state}</th>
<td>{curElem.Confirmed}</td>
<td>{curElem.recovered}</td>
<td>{curElem.deaths}</td>
<td>{curElem.active}</td>
<td>{curElem.lastupdatedtime}</td>
</tr>
)
: <p> No data available </p>
})
}

What should I do to successfully map data from axios API?

How do I map out the data I've put in my console/state? I've been trying to add a map function where I left the "//m", and it seems like it should be simple enough but I can't seem to do it properly.
import React, { useState, useEffect } from "react";
import axios from "axios";
import EmployeeDetail from "./EmployeeDetail";
function App() {
const [employees, setEmployees] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
axios.get("https://randomuser.me/api/?results=10&nat=us")
.then(res => {
console.log(res.data.results);
setEmployees(...res.data.results);
setLoading(false);
})
.catch(err => {
console.log(err);
});
}, []);
return (
<div className="App">
<h1>Employee List</h1>
//m
</div>
);
}
export default App;
I was able to make it using the API the guy in the youtube video I referenced used ("https://restcountries.eu/rest/v2/all") with the following function:
{countries.map((country) => (
<div key={country.name}>
{country.name} - {country-capital}
</div>
))}
I'm just having problems with doing it with my own API.
From your question it seems you are looking for rendering a table of output data from an API call.
When you call setEmployees(), react application will refresh the page using virtual DOM as you are setting a state using react hooks mechanism.
return(){
<div className="App">
<h1>Employee List</h1>
<table>
<thead>
// your table headers
</thead>
<tbody>
{this.employees.map((item, index) => {
<tr>
<td>{item.value1}</td>
<td>{item.value2}</td>
// as per your requirement
</tr>
})}
</tbody>
</table>
</div>
}
One more thing you can do is, create a function and return JSX from function.
Please visit below link for creating function and returning JSX.
How to loop and render elements in React.js without an array of objects to map?
You can use map as you want.
return (
<div className="App">
<h1>Employee List</h1>
<ul>
{
emplyees.map((employee) =>
<li>{employee.name}</li>
);
}
</ul>
</div>
);
There is a detailed document that you could follow step by step here

Why is my data not displaying in the table in react

Does anyone know why my data isn't displaying, it console.logs 'x[0]', 'x[1]', 'x[2]', and 'x[3]' fine in my return statement. I'm pretty new to react and programming in general so I have no idea why this doesn't work.
I would just expect it to fill the rows of the table like the 2 I've manually coded in.
import React, { useState, useEffect } from 'react'
import "./stylesheets/oddsmatcher-table.css"
const App = () => {
const [wow, setWow] = useState([])
useEffect(() => {
fetch(DATA)
.then(res => res.json())
.then(data => {
const newData = data.data.slice(0, 10)
const k = newData.map(x => {
return [x.date, x.event_name, x.bookmaker_name, x.exchange]
})
setWow(k)
console.log(k)
})
}, [])
return(
<table>
<tbody>
<tr>
<th>Date</th>
<th>Event</th>
<th>Bookie</th>
<th>Exchange</th>
</tr>
<tr>
<td>25-09-2020</td>
<td>Man United vs Liverpool</td>
<td>Bet365</td>
<td>Smarkets</td>
</tr>
<tr>
<td>26-09-2020</td>
<td>Arsenal vs Man City</td>
<td>Coral</td>
<td>Betfair Exchange</td>
</tr>
{wow.forEach(x => {
return(
<tr>
<td>{x[0]}</td>
<td>{x[1]}</td>
<td>{x[2]}</td>
<td>{x[3]}</td>
</tr>
)
})}
</tbody>
</table>
)
}
export default App
Update: Try switching your wow.forEach to this:
{wow.map((x, index) => {
return (
<tr key={index}>
{x.map((dataPiece) => (
<td key={dataPiece}>{dataPiece}</td>
))}
</tr>
);
})}
Here's the Codesandbox I was using to test. I replaced your async fetch with a global variable with what I think your wow data looks like:
https://codesandbox.io/s/suspicious-glitter-mf0tg?fontsize=14&hidenavigation=1&theme=dark
Let me know if that works. If it doesn't, can you post an example of what your fetched data looks like?

How can I pass props to another components with in reactjs

I'm trying to pass product data from AllProducts component to Product component.
AllProducts.jsx: is showing all the products I have and Product.jsx will show specific product and how can I pass data to Product.jsx?
Here is my AllProducts.jsx:
const AllProducts = (props) => {
const [products, setProducts] = useState([]);
const getProductsAPI = () => {
axios
.get("http://localhost:8000/api/products")
.then((res) => {
setProducts(res.data);
getProductsAPI();
})
.catch((err) => {
console.log(err);
});
};
useEffect(() => {
getProductsAPI();
}, [props]);
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{products.map((product, i) => (
<tr key={i}>
<th scope="row">{i}</th>
<td>{product.title}</td>
<td>
<Link to={`/products/${product._id}`}> View </Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
and here is my Product.jsx:
const Product = (props) => {
return (
<div className="container">
<h4>{props.product.title}</h4>
</div>
);
};
export default Product;
Here is my project github if you want to look at all the code I have: https://github.com/nathannewyen/full-mern/tree/master/product-manager
If the data is fully loaded for each product in AllProducts, and you don't want to make another API call by product id in the Product component, in this case, you don't have to use a route link to view Product, just make a conditional rendering to show Product component inside AllProducts component. pseudo-code as below,
const [showProduct, setShowProduct] = useState(false);
const [currentProduct, setCurrentProduct] = useState();
const showProduct = (product) => {
setShowProduct(true);
setCurrentProduct(product);
}
<tbody>
{products.map((product, i) => (
<tr key={i}>
<th scope="row">{i}</th>
<td>{product.title}</td>
<td>
<button type="button" onclick = {showProduct(product)}>View</button>
</td>
</tr>
))}
</tbody>
return (showProduct ? <Product /> : <AllProucts/>)
If you also need to make another API call to get extra data for each product, then use the router link but perhaps you can not pass props.

TypeError: books.map is not a function react

I'm trying to get my api to display the data but it keeps returning the error books.map is not a function. I'm aware my array is empty when the page loads but and it may need a (books || []) but that didn't work either.. any ideas?
I just want to be able to map the data into the table and then manipulate it. When I console.log(books) I get the data I want but the map doesn't work.
My code:
import PropTypes from "prop-types";
import BookService from "../services/BookService";
import Books from "./Books";
import axios from "axios";
import { Table, Container } from "react-bootstrap";
const BooksList = () => {
const [books, setBooks] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [booksPerPage, setBooksPerPage] = useState(10);
useEffect(() => {
const fetchBooks = async () => {
const res = await axios.post("http://nyx.vima.ekt.gr:3000/api/books");
setBooks(res.data);
console.log(setBooks);
setLoading(false);
};
fetchBooks();
}, []);
console.log(books, "BooksList");
return (
<Container>
<div className="container mt-5">
<h1 className="text-primary mb-3"> Books </h1>
<Table striped bordered hover size="lg">
<thead>
<tr>
<th>#</th>
<th>Book Author</th>
<th>Book Pages</th>
<th>Book Publication City</th>
<th>Book Publication Country</th>
<th>Book Publication Year</th>
<th>Book Title</th>
</tr>
</thead>
{books.map(book => (
<tbody>
<tr>
<td>{book.id}</td>
<td>{book.book_pages}</td>
</tr>
</tbody>
))}
</Table>
</div>
</Container>
);
};
export default BooksList;
As Jay said, you should do setBooks(res.data.books) but I would also advise you to control an error from API result, if the API is down the front-end should know how to manage that errors instead of crashing. One way to do this is check whether the contetn of res.data.books is an array or not.
Your full code should look something like this:
import PropTypes from "prop-types";
import BookService from "../services/BookService";
import Books from "./Books";
import axios from "axios";
import { Table, Container } from "react-bootstrap";
const BooksList = () => {
const [books, setBooks] = useState([]);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [booksPerPage, setBooksPerPage] = useState(10);
useEffect(() => {
const fetchBooks = async () => {
try {
setError(false);
setLoading(true);
const res = await axios.post("http://nyx.vima.ekt.gr:3000/api/books");
setBooks(res.data.books);
console.log(setBooks);
setLoading(false);
} catch(err) {
console.log(err);
setError(true);
setLoading(false);
setBooks([]);
}
};
fetchBooks();
}, []);
console.log(books, "BooksList");
if(error) return <div>Error message</div>
return (
<Container>
<div className="container mt-5">
<h1 className="text-primary mb-3"> Books </h1>
<Table striped bordered hover size="lg">
<thead>
<tr>
<th>#</th>
<th>Book Author</th>
<th>Book Pages</th>
<th>Book Publication City</th>
<th>Book Publication Country</th>
<th>Book Publication Year</th>
<th>Book Title</th>
</tr>
</thead>
{books.map(book => (
<tbody>
<tr>
<td>{book.id}</td>
<td>{book.book_pages}</td>
</tr>
</tbody>
))}
</Table>
</div>
</Container>
);
};
export default BooksList;
You have to set the data like this because of all the response data are in the books properties
setBooks(res.data.books);

Resources