I couldn't map the second API response https://api.coingecko.com/api/v3/global with error prompted (read property 'map' of undefined), while the first API is fine.
Whats the issue here?
export default function Home(props) {
const { data } = props.result;
const { global } = props.nextResult;
<table className="table2 table-hover table-dark">
<thead>
<tr>
<th>Markets</th>
</tr>
</thead>
<tbody>
{global.map (gg => (
<tr key={gg.endedicos}>
<td>{gg.markets}</td>
</tr>
))}
</tbody>
</table>
export async function getServerSideProps(context) {
const params = {
order: CoinGecko.ORDER.MARKET_CAP_DESC
};
const [result, nextResult] = await Promise.all([
coinGeckoClient.coins.markets({params}),
coinGeckoClient.global()
]);
return {
props: {
result, nextResult
},
}
}
Related
here i am fetching data from API which is giving me response in "array of objects" i want to store it in the array called products and want to display it on the page.
Here is my code
import React, { useState, useEffect } from "react";
import '../all.css';
import Axios from "axios";
const AllProduct = () => {
const [products, setProducts] = useState([]);
const fetchProducts = async () => {
const { data } = await Axios.get(
"http://localhost:8080/api/QueryAllProducts"
);
console.log(data.response);
setProducts(data.response);
console.log(products);
};
const display = () => {
return (products ?? []).map(product => (
<tr key={product.id}>
<th>{product.id}</th>
<th>{product.name}</th>
<th>{product.area}</th>
<th>{product.ownerName}</th>
<th>{product.cost}</th>
</tr>
) );
}
useEffect(() => {
fetchProducts();
}, []);
return (
<div>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Area</th>
<th>Owner Name</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
{display()}
</tbody>
</table>
</div>
)
}
export default AllProduct;
I have used ReactJS for frontend and NodeJS
here is the screenshot of what i am getting on console
Check that the type of products is array. If it is an object, an error occurs.
I am trying to fetch data from backend, I want to load all data which are in database, when I load function then getting an error like "User.map is not a function", please let me know where am wrong.
User.js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { getUsers } from "./apis";
const UserData = () => {
const [users, setUser] = useState([]);
useEffect(() => {
AllUsers();
}, []);
const AllUsers = async () => {
const response = await getUsers();
console.log(response.data);
setUser(response.data ? response.data : []);
};
return (
<div>
<div className="container">
<table className="table table-hover table-bordered mt-5">
<thead>
<tr>
{/* <th scope="col">No</th> */}
<th scope="col">Title</th>
<th scope="col">Details</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{users.map((user, index) => (
<tr key={index}>
<th scope="row">{user.id}</th>
<td>{user.title}</td>
<td>{user.description}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};
Api.js
I have added api.js file please check it , and let me know where am wrong
export default UserData;
import Axios from "axios";
const url = "http://localhost:3000/";
export const getUsers = async (id) => {
id = id || "";
return await Axios.get(`${url}/${id}`);
};
export const deleteUser = async (id) => {
return await Axios.delete(`${url}/${id}`);
};
You can use Optional chaining (?.) for check the data is available or not. Because while API's is calling data not set in your state. It's might be a undefined.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const dogName = adventurer.dog?.name;
console.log(dogName);
In your case do with this way.
{users?.map((user, index) => (
<tr key={index}>
<th scope="row">{user.id}</th>
<td>{user.title}</td>
<td>{user.description}</td>
</tr>
))}
import Axios from "axios";
const url = "http://localhost:3000/";
export const getUsers = async (id) => {
id = id || "";
return await Axios.get(`${url}/${id}`);
};
export const deleteUser = async (id) => {
return await Axios.delete(`${url}/${id}`);
};
so I'm making a mini eCommerce app using MERN stack, i'm fetching products for each seller using his id, so he's the only one who can edit or delete his own products,
in my component i get the user's id from redux state from the user, then i use the id to fetch products for each logged in seller.(in useEffect)
so fetching products depends on the user, and the user is always loaded and no need to fetch it after he login.
the problem is, only the first time after i login and i render the component it gives me
TypeError: products.map is not a function. but if i refresh the page it works fine
so it doesn't see products the first time idk why even if the user is there and the id to fireup the fetching function.
function EditProducts() {
const { user } = useSelector(state => state.userrr);
const { loading, products } = useSelector(state => state.userProductsss);
const dispatch = useDispatch();
useEffect(() => {
console.log(user);
console.log(products);
if (!user) {
return;
} else {
let id = user._id;
dispatch(fetchUserProducts(id));
}
}, [dispatch, user]);
const deleteIt = id => {
dispatch(deleteProduct(id))
.then(res => {
toast.success(res, { position: toast.POSITION.BOTTOM_LEFT });
})
.catch(error => {
toast.error(error, {
position: toast.POSITION.BOTTOM_LEFT,
autoClose: false
});
});
};
console.log(products);
return (
<Container>
<Table striped bordered hover variant='dark'>
<thead>
<tr>
<th>category</th>
<th>Description</th>
<th>Price</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{loading && (
<tr>
<td colSpan='4'>
<Spinner animation='border' /> loading...{" "}
</td>
</tr>
)}
{!user && !loading && (
<tr>
<td colSpan='4'>Please Log in to access this page</td>
</tr>
)}
{products.map(product => (
<tr key={product._id}>
<td>{product.name}</td>
<td>{product.description}</td>
<td>${product.price}</td>
<td>
<span className='btn btn-primary mr-3'>
<UpdateProductForm
id={product._id}
name={product.name}
description={product.description}
category={product.category}
price={product.price}
numberInStock={product.numberInStock}
productImage={product.productImage}
/>
</span>
<Button className='btn btn-danger' onClick={() => deleteIt(product._id)}>
<FontAwesomeIcon icon={faTrash} />
</Button>
</td>
</tr>
))}
</tbody>
</Table>
</Container>
);
}
export default EditProducts;
this is my reducer
const productReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_USER_PRODUCTS_STARTED:
return {
...state,
loading: true
};
case FETCH_USER_PRODUCTS_SUCCESS:
return {
...state,
loading: false,
error: null,
products: action.payload.products
};
case FETCH_USER_PRODUCTS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error,
success: null
};
default:
return state;
}
};
this is the actions
export const fetchUserProducts = userId => {
return dispatch => {
dispatch(fetchUserProductsStarted());
axios
.get(`/api/product/${userId}/products`)
.then(res => {
dispatch(fetchUserProductsSuccess(res.data));
})
.catch(error => {
dispatch(fetchUserProductsFailure(error.message));
});
};
};
const fetchUserProductsStarted = () => {
return {
type: FETCH_USER_PRODUCTS_STARTED
};
};
const fetchUserProductsSuccess = products => {
return {
type: FETCH_USER_PRODUCTS_SUCCESS,
payload: {
products
}
};
};
const fetchUserProductsFailure = error => {
return {
type: FETCH_USER_PRODUCTS_FAILURE,
payload: {
error
}
};
};
so the problem was that useEffect couldn't be able to ensure the user data is loaded before the first render here:
const { user } = useSelector(state => state.userrr);
so the user was null, so it couldn't get the products depending on the user id.
what i did is that i loaded the user again inside the component useEffect so it gets the user data.
useEffect(() => {
dispatch(loadUser());
const id = user ? user._id : null;
dispatch(fetchUserProducts(id));
}, [ dispatch, id]);
import React, { Component } from "react";
import axios from "axios";
class DisplyDish extends Component {
state = { posts: [] };
componentDidMount() {
axios
.get("http://localhost:8888/api/v1/dish") //returns promise
.then(response => {
this.setState({ posts: response.data });
console.log("response:", response.data);
})
.catch(err => {
console.log("err:", err);
});
}
render() {
return (
<>
<table>
<tbody>
<tr>
<th>id</th>
<th>title</th>
<th>type</th>
<th>weight</th>
<th>originalPrice</th>
<th>offerPrice</th>
<th>description</th>
<th>quantity</th>
<th>status</th>
<th>rating</th>
<th>image</th>
</tr>
{this.state.posts.map(post => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.title}</td>
<td> {post.type}</td>
<td> {post.weight}</td>
<td>{post.originalPrice}</td>
<td>{post.offerPrice}</td>
<td>{post.description}</td>
<td>{post.quantity}</td>
<td>{post.status}</td>
<td>{post.rating}</td>
<td>
<img
src={"http://localhost:8888/api/v1/dish/" + post.image}
alt="image"
/>
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default DisplyDish;
and this is what i'm getting in console
id: 3
image: "uploads/dish/image_1581159803092.jpg"
import React, { Component } from "react";
import axios from "axios";
import "./getForm.css";
class GetData extends Component {
state = { posts: [] };
componentDidMount() {
axios
.get("http://localhost:8888/api/v1/user") //returns promise
.then((response) => {
this.setState({ posts: response.data });
console.log("response:", response.data);
})
.catch((err) => {
console.log("err:", err);
});
}
render() {
return (
<>
<h1>Posts</h1>
<table>
<tbody>
<tr>
<th>id</th>
<th>name</th>
<th>email</th>
<th>mobile</th>
<th>status</th>
</tr>
{this.state.posts.map((post) => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.name}</td>
<td> {post.email}</td>
<td> {post.mobile}</td>
<td>
<img src={post.image} />
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default GetData;
You can add routes for your photos into Node.js public folder:
...
app.use('/photos', express.static(__dirname + '/public/photos'));
...
Then return image_url from http://localhost:8888/api/v1/user, the URL can be like http://localhost:8888/api/v1/photos/your_image_name.jpg
In your React:
...
<img style={{width:500, height:500}} src={post.image_url)} />
...
Note: Assuming you have the image URL's on your server response.
The posts state is being mapped before you receive the response from your server on the initial render. You can add a loading state which is set to true initially and after the response.data is set in the posts state, you can set loading to false.
You can then conditionally render the whole component based on this loading state like this.
Here is a link to a working sandbox.
import React, { Component } from "react";
import axios from "axios";
class GetData extends Component {
state = { posts: [], loading: true };
componentDidMount() {
this.fetchUserData();
}
fetchUserData = async () => {
try {
const response = await axios.get("http://localhost:8888/api/v1/user");
this.setState({ posts: response.data, loading: false });
console.log(response.data);
} catch (error) {
this.setState({ loading: false });
console.log(error);
}
};
render() {
if (this.state.loading) {
return "Loading";
}
return (
<>
<h1>Posts</h1>
<table>
<tbody>
<tr>
<th>id</th>
<th>name</th>
<th>email</th>
<th>mobile</th>
<th>status</th>
</tr>
{this.state.posts.map((post) => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.name}</td>
<td> {post.email}</td>
<td> {post.mobile}</td>
<td>
<img src={post.image} />
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default GetData;