fetching data not showing in table in react - reactjs

I am create a table and fetching data using axios but in the table I am not able to print the data when I check data is printing in browser but not able to print the particular data to a table format so what should be change in my code?
import { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Table } from "react-bootstrap";
import axios from "axios";
export default function App() {
const [user, setUser] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users", (req, res) => {
res.json();
})
.then((data) => setUser({ ...user, data }))
.catch((error) => console.error(error));
});
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{user?.data?.length > 0 &&
user.data.map((user) => {
return (
<tr key={user.id}>
<td>{JSON.stringify(user.data["data"].id)}</td>
<td>{JSON.stringify(user.data["data"].name)}</td>
<td>{JSON.stringify(user.data["data"].username)}</td>
<td>{JSON.stringify(user.data["data"].email)}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user.data["data"])}</div> */}
</div>
);
}

for example
import { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Table } from "react-bootstrap";
import axios from "axios";
export default function App() {
const [user, setUser] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((res) => {
setUser(res.data);
})
.catch((error) => console.error(error));
}, []);
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{user?.length > 0 &&
user.map((userData) => {
return (
<tr key={userData.id}>
<td>{userData.id}</td>
<td>{userData.name}</td>
<td>{userData.username}</td>
<td>{userData.email}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user)}</div> */}
</div>
);
}

Replace the useEffect code as follow.
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((data) => setUser({ ...user, data }))
.catch((error) => console.error(error));
}, []);

You already know that calling this api will give you an array of users so you can initialise the state as empty array as:
const [users, setUsers] = useState([]);
and when you are using axios then you don't have to use res.json(). axios will do it for you out of the box.
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(({ data }) => setUsers(data))
.catch((error) => console.error(error));
so, after getting data using get method of axios it will return you a promise and you can get data from its data property that is passed an first args. You can directly set state which will be an array of objects.
.then(({ data }) => setUsers(data))
Here I've destructed the object to get only the data property.
Since users will be an array of objects, so you don't have to do any check. You can directly use user.id to get the respective property.
Codesandbox link
export default function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(({ data }) => setUsers(data))
.catch((error) => console.error(error));
}, []);
return (
<div className="App">
<h3 className="text-primary">User List</h3>
<Table
variant="danger"
striped
bordered
hover
className="shadow-lg text-center"
>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>UserName</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{users.map((user) => {
return (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <div>{JSON.stringify(user.data["data"])}</div> */}
</div>
);
}

Related

How can i change this code to react redux

Here i want to change this code to react redux. How i can change this code using react redux. Kindly provide any solutions for changing this code to react redux using GET method api. As iam new to react js how can i change this code using react redux.
import React from "react";
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
export default function User() {
const [users, setUsers] = useState([]);
const f = async () => {
const res = await fetch("https://reqres.in/api/userspage=1");
const json = await res.json();
setUsers(json.data);
};
useEffect(() => {
f();
}, []);
const handleLogout = (e) => {
localStorage.clear();
window.location.pathname = "/";
}
return (
<div>
<h1>List Users</h1>
<div>
<button onClick={handleLogout}>Logout</button>
<nav>
<Link to="/Home">Home</Link>
</nav>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>First_name</th>
<th>Last_name</th>
<th>Email</th>
<th>Avatar</th>
</tr>
</thead>
<tbody>
{users.length &&
users.map((user) => {
return (
<tr>
<td> {user.id}</td>
<td>{user.first_name}</td>
<td> {user.last_name} </td>
<td>{user.email}</td>
<td> <img key={user.avatar} src={user.avatar} alt="avatar" /></td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}

React componentDidMount vs useEffect hooks for API call

When I am trying to make an API call using in useEffect hook (before the component did mount), somehow the state is not getting updated, hence I am getting an error Cannot read property of undefined.
But if I am converting the same logic to a Class component and making the API call in the componentDidMount function, the code works well.
Could anyone tell me why?
Using useEffect
import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";
export default function Customers() {
const [customers, setCustomers] = useState([]);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
console.log(customers);
}, [customers]);
return (
<div className="container-fluid d-flex flex-column align-items-center justify-content-center">
<div className="top">Customers</div>
<div className="tables">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{customers.data.map((customer) => ( // error on this line.
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
Class Based Component
import React, { Component } from "react";
import axios from "axios";
import "./Customers.css";
export default class Customers extends Component {
state = {
customers: [],
};
componentDidMount() {
axios
.get("http://localhost:5000/customers")
.then((res) => {
res.data.sort();
console.log(res.data);
this.setState({ customers: res.data });
})
.catch((err) => console.log(err));
}
render() {
return (
<div className="container-fluid main w-75 my-4 d-flex flex-column align-items-center">
<div className="top p-4 d-flex justify-content-center">
Our Customers
</div>
<div className="tables w-100">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{this.state.customers.map((customer) => (
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
}
You are not setting state properly in useEffect hook. instead of setCustomers({data:data}); it should be just setCustomers(data);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
Now because customers is an array, just map over customers instead of customers.data.map.
customers.map((customer)=>{})
So the final code will be
import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";
export default function Customers() {
const [customers, setCustomers] = useState([]);
useEffect(() => {
axios
.get("http://localhost:5000/customers")
.then((res) => {
const data = res.data;
setCustomers(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
console.log(customers);
}, [customers]);
return (
<div className="container-fluid d-flex flex-column align-items-center justify-content-center">
<div className="top">Customers</div>
<div className="tables">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Account No</th>
<th scope="col">Name</th>
<th scope="col">E-mail</th>
<th scope="col">Balance</th>
</tr>
</thead>
<tbody>
{customers.map((customer) => (
<tr>
<th scope="row">{customer.account_no}</th>
<td>{customer.name}</td>
<td>{customer.email}</td>
<td>{customer.balance}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
You are declaring your customers state as an array:
const [customers, setCustomers] = useState([]);
But you are passing an object after fetching the data:
setCustomers({ data: data });
That's why your map iteration in the return section fails, because you are setting the state to an object and not an array. If data is an array you should only assign it like this:
setCustomers(data);
The componentDidMount works because you are assigning res.data directly to the customers state and it turns out to be similar to:
setCustomers(data);

Redux-thunk dispatch is not a function error

I tried to call an action from my component. But, When I run the call the below action from my component
I got a type error that tells that dispatch is not a function. how to get rid of this error.
action:
import { FETCH_ALL, FETCH_CUSTOMER, CREATE_CUSTOMER, DELETE_ALL, DELETE_CUSTOMER, UPDATE_CUSTOMER } from '../actionTypes';
import * as api from '../api/index';
export const getCustomers = () => async (dispatch) => {
try {
const { data } = await api.getCustomers();
console.log(dispatch);
dispatch({ type: FETCH_ALL, payload: data});
} catch(err) {
console.log(err);
}
};
component:
function Home() {
const customers = useSelector((state) => state.customers);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getCustomers);
},[dispatch]);
return (
<div style={{paddingLeft: '50px', paddingRight: '50px'}}>
<header>
<h1 style={{textAlign: 'center', color: 'green'}}>Customer Relationship Management</h1>
</header>
<button onClick={dispatch(getCustomers)}>Fetch Customers</button>
<div className="heading">
<h3>Customer Details: </h3>
<button className="homePageButtons"><Link className="homePageLinks" to="/add-customer">Add Customer</Link></button>
</div>
<div className="customerTable">
<table>
<thead>
<tr>
<th>ID</th>
<th className="name">First Name</th>
<th className="name">Last Name</th>
<th className="email">Email</th>
</tr>
</thead>
<tbody>
{customers.map((customer) => (
<tr>
<td>customer.id</td>
<td>customer.firstName</td>
<td>customer.lastName</td>
<td>customer.email</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
The below error occurs:
customer.js:11 TypeError: dispatch is not a function
at customer.js:9
I log the dispatch, it is showing the below object...
SyntheticBaseEvent {_reactName: "onClick", _targetInst: null, type: "click", nativeEvent: MouseEvent, target: button, …}
I applied the middleware in the index.js file ad below...
const store = createStore(reducers, compose(applyMiddleware(thunk)));
In useEffect do dispatch(getCustomers()); in the click handler do onClick={()=>dispatch(getCustomers())}

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