How to properly map results from api fetch react - reactjs

I've got my fetch request setup and properly retrieving the data from the API. However, I'm receiving the 'Unhandled Rejection (TypeError): items.map is not a function' error when I try to map the results into list items. How am I meant to map out the 'titles' into deliverables?
Here's my current setup:
Output of fetch request
{1: {…}, 2: {…}, 3: {…}, 4: {…}, 6: {…}, 7: {…}, 8: {…}, 9: {…}}
1:
entries: "598"
id: "1"
title: "Newsletter SignUp"
__proto__: Object
2: {id: "2", title: "Contact Page Form", entries: "663"}
3: {id: "3", title: "Sidebar RFI", entries: "114"}
4: {id: "4", title: "White Paper Email Sign-Up", entries: "72"}
6: {id: "6", title: "White Paper Registration", entries: "84"}
7: {id: "7", title: "Services RFI", entries: "766"}
__proto__: Object
Code to fetch / render from api
componentDidMount() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", "Basic XXX");
var requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow'
};
fetch("https://www.example.com/wp-json/gf/v2/forms", requestOptions)
.then(res => res.json())
.then(
(result) => {
console.log(result);
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error,
isLoaded,
items
} = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
<div>
{items.map(item => (
<li key={item.title}>
{item.title}
</li>
))}
</div>
</div>
);
}
}

This is a question about javascript basics, not react or apis. The question is really how to map over an object with object as values.
One way is to get the keys (like SomoKRoceS shows) is Object.keys:
Object.keys(obj).map(key => (
<li key={obj[key].title}>
{items[obj].title}
</li>
))
Another way is to "for in" :
for (const key in obj) {
if (obj.hasOwnProperty(prop)) {
list.push(<li key={obj[key].title}>{items[obj].title}</li>)
}
}
return list;
Another way is Object.values:
Object.values(obj).map(val => <li key={val.title}>{val.title}</li>)

You can do something like this:
export default class Example extends React.Component {
// Your state will look something like this after the get request
state = {
result: {
1: { id: "1", title: "Contact Page Form", entries: "663" },
2: { id: "2", title: "Contact Page Form", entries: "663" },
3: { id: "3", title: "Sidebar RFI", entries: "114" },
4: { id: "4", title: "White Paper Email Sign-Up", entries: "72" },
6: { id: "6", title: "White Paper Registration", entries: "84" },
7: { id: "7", title: "Services RFI", entries: "766" }
}
};
renderResult = () => {
const res = Object.values(this.state.result);
return res.map(item => <div>{item.title}</div>);
};
render() {
return <div>{this.renderResult()}</div>;
}
}
Live demo here: https://codesandbox.io/s/polished-river-kueyq?file=/src/App.js:51-738

map() is a method applied on arrays. You can create an array of all indexes of the object, and then map over it - for each element, get the value of that key from the original object.
So you can do something like this:
return (
<div>
<div>
{Object.keys(items).map(item => (
<li key={items[item].title}>
{items[item].title}
</li>
))}
</div>
</div>
);
Object.keys(items) will create an array of all keys in items which is [1,2,3,...], then the map will iterate over that array and you will be able to access the desired object with that key with items[item].

Related

How to fetch array objects from api using axios?

Im fetching data from api using axios.
I have array of objects.
I would like to fetch objects inside array.
Here is api : https://51fgc922b7.execute-api.ap-south-1.amazonaws.com/dev/productpreview?product_id=122003
enter image description here
Here is what i tried !
useEffect(() => {
if (props.product_id) {
axios.
get(`https://51fgc922b7.execute-api.ap-south-1.amazonaws.com/dev/productpreview?product_id=${props.product_id}`)
.then((res) => {
console.log(res.data)
setModelData(res.data.data[0])
})
.catch((error) => {
setIsErrorImage(true)
})
}
}, []);
Im able to fetch data but what im trying to achive is that, there are three objects with camera objects called 0,1,2 and i want to fetch them.
I'm not sure about your requirement but as far as I understood you just want the array of objects from the data you get. You can get that simply by traversing the object like
const cameraData = res.data.reduce((acc,el) => [...acc, ...el.camera], [] )
console.log(res.data) if correct ,
setModelData(res.data)
and in return example ;
modelData.map((item)=> {
return (
<div> {item.camera.map((data)=>{
return (
<div> {data.camera_beta} </div>
)
})}
</div> )})
this is what i want to tell
const [modelData, setModelData] = useState([
{
name: 'Electronics',
slug: 'electronics',
count: 11,
items: [
{ name: 'Phones', slug: 'phones', count: 4 },
{ name: 'Tablets', slug: 'tablets', count: 5 },
{ name: 'Laptops', slug: 'laptops', count: 2 },
],
},
{
name: 'Clothing',
slug: 'clothing',
count: 12,
items: [
{ name: 'Tops', slug: 'tops', count: 3 },
{ name: 'Shorts', slug: 'shorts', count: 4 },
{ name: 'Shoes', slug: 'shoes', count: 5 },
],
}
])
you have data like this.
this way you set the data into setmodeldata in useeffect.
in useffect after set
console.log(modelData) and
console.log(modelData[0])
you can see the difference between the two.one comes in the form of an object and the other as an array.
at most you can map them

Getting [object Object] instead of object in React

I'm fetching an array of objects in my React application. Later I am returning a Product component to each object.
const [products, setProducts] = useState([]);
useEffect(() => {
fetch("http://localhost:8080/products")
.then(resp => resp.json())
.then(resp => {
console.log(resp); //line 55
setProducts(resp)
})
}, []);
return (
<div>
{products.map(product => {
return <Product product={product} />
})}
</div>
);
This is result of my console.log(resp) in line 55:
Array(6) [ {…}, {…}, {…}, {…}, {…}, {…} ]
​
0: Object { id: 1, name: "prod 3", amount: 30, … }
​​
active: true
​​
amount: 30
​​
id: 1
​​
name: "prod 3"
​​
<prototype>: Object { … }
​
1: Object { id: 23, name: "prod 2", amount: 20, … }
​
2: Object { id: 4, name: "Angular course", amount: 19, … }
​
3: Object { id: 42, name: "peanut butter", amount: 13, … }
​
4: Object { id: 43, name: "soup", amount: 12, … }
​
5: Object { id: 15, name: "hot-dog", amount: 11, … }
​
​
length: 6
​
<prototype>: Array []
So I am passing a single object to my Product component. However, when I want to view the passed object in the logs, I get the object inside the object:
const Product = (product) => {
console.log(product); // result: Object { product: {…} }
}
Why am I getting an object inside an object instead of a single object?
In react the argument for a component is always their props object. This is an object with all the properties you define in the tag. So, for example if you define <Product anotherProp={anotherProp} product={product} /> you would get a props object with the keys product and anotherProp.
So the correct way to get the product is through destructuring assingment.
const Product = (props) => {
const {product} = props;
console.log(product); // result: Object { product: {…} }
}
If you wish that your props object is exactly your product object you have to change the way you set your tag... In your case, it would be something like this...
const [products, setProducts] = useState([]);
useEffect(() => {
fetch("http://localhost:8080/products")
.then(resp => resp.json())
.then(resp => {
console.log(resp); //line 55
setProducts(resp)
})
}, []);
return (
<div>
{products.map(product => {
return <Product {...product} />
})}
</div>
);

how to loop through two array in react?

I'm trying to get my data from 2 arrays:
Here is my function:
function Cart({ basketProps }) {
let productsInCart = [];
Object.keys(basketProps.products).forEach(function (item) {
if (basketProps.inCart) {
productsInCart.push(basketProps.products);
}
console.log(productsInCart);
});
...
...
...
}
when i do console.log it return me this:
[{…}]
0:
products: Array(1)
0:
img_url1: "https://thebeuter.com/wp-content/uploads/2020/06/38-1.jpg"
price: 1290000
title: "BEUTER BACK2BACK ZIPPER WHITE JACKET"
__proto__: Object
length: 1
__proto__: Array(0)
__proto__: Object
length: 1
__proto__: Array(0)
How can I use .map to loop thru these?
Updated:
When I do console.log(basketProps). It gave me this:
basketNumbers: 1
cartCost: 1290000
inCart: true
numbers: 1
products:
products: Array(1)
0: {title: "BEUTER BACK2BACK ZIPPER WHITE JACKET", price: 1290...}
You dont require the 'Object.keys' function, since inCart is already available at outer level.
if (basketProps.inCart) {
productsInCart.push(basketProps.products);
}
let total =0;
productsInCart.map(cartProduct=>{
total = total + cartProduct.price;
}
You can run the map function on productInCart array like above.
To select all products inCart use:
filter to select all products inCart
map (or flatMap) to select products property you're interested in
I use flatMap because it makes list easier to render - it makes an array of products, not an array of product arrays. flatMap first maps each element using a mapping function, then flattens the result into a new array (it is identical to a map() followed by a flat() of depth 1).
function App() {
return <Cart basketProps={DATA} />;
}
function Cart({ basketProps }) {
const productsInCart = basketProps
.filter(product => product.inCart)
.flatMap(product => product.products);
return (
<div className="App">
<ul>
{productsInCart.map(product => (
<li>{product.title}</li>
))}
</ul>
</div>
);
}
const DATA = [
{ inCart: true, products: [
{ title: "PRODUCT 1", price: 10 },
{ title: "PRODUCT 2", price: 20 }
]},
{ inCart: false, products: [
{ title: "PRODUCT 3", price: 30 },
{ title: "PRODUCT 4", price: 40 }
]},
{ inCart: true, products: [
{ title: "PRODUCT 5", price: 50 },
{ title: "PRODUCT 6", price: 60 }
]}
];
ReactDOM.render(<App />, 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 assume basketProps.products is an object array which has list of products, and has inCart = true if the product is in cart
In that case your code to get the products in cart should be like this
let productsInCart = [];
if(basketProps && Array.isArray(basketProps.products)) {
productsInCart = basketProps.products.filter(function (item) {
return item.inCart ;
});
}
console.log(productsInCart )
or if you are using arrow functions, the one liner would be (add array validation as in example above)
let productsInCart = basketProps.products.filter((item)=>(item.inCart));
console.log(productsInCart);

TypeError: posts is not iterable returning data from firebase

I'm new using react and firebase.
I try to get posts from firebase:
useEffect(() => {
setLoading(true);
setError(false);
let cancel;
// get posts
var postsRef = firebase.database().ref('/posts/');
postsRef.on('value', function(snapshot) {
setPosts(prevPosts => {
var posts = snapshot.val();
console.log(posts);
return [...prevPosts,...posts]
});
});
setLoading(false);
}, [ pageNumber ]);
The problem is it gives me:
TypeError: posts is not iterable on return [...prevPosts,...posts]
any ideas how to solve this? this will return data to a function that will parse data like this:
return (
<>
{posts.map((post, index) => {
return <Post key={post.id} id={post.id} ref={ref} img={post.img} titulo={post.titulo} />
})}
</>
)
Why I get this error? how can I parse my data correctly?
thanks!
Since your post variable is an object like:
{
"-M5GmoelPzWryNizVjww": { img: "img/", titulo: "title 1", user: "root" },
"-M5GmsTDcbDYZuoYBVIt": { img: "img/", titulo: "title 2", user: "root" },
"-M5GmxMZMzZe9p5uDuWe": { img: "img/", titulo: "title 3", user: "root" },
"-M5GmyKDbbtxR8Dw3-J2": { img: "img/", titulo: "title 4", user: "root" },
"-M5GmzHjK1PQJ2ulrCTi": { img: "img/", titulo: "title 5", user: "root" },
"-M5Gn2Rsv_OrwL1GkbVG": { img: "img/", titulo: "title 6", user: "user" },
"-M5Gn39y9JDishOdxwi4": { img: "img/", titulo: "title 7", user: "user" }
}
You should transform it previously to an array so that you can concatenate it to your previous list of posts. To do so, and using the key of the object as an id, you can use:
return [...prevPosts, ...Object.keys(posts).map(key => ({
id: key,
...posts[key]
}))];

how to access a particular object element in array

I have used a map function to using reduce and I got an array of objects.
How can I get a particular value in the "return"?
Below is the console output
{design job: Array(2)}
design job: Array(2)
0:
fullName: "Rakesh"
phoneno: "1111111111"
__proto__: Object
1:
fullName: "test user"
phoneno: "9176837787"
__proto__: Object
length: 2
__proto__: Array(0)
__proto__: Object
Below is my code
const list = appliedCandidates.reduce(
(appliedCandidate, { Title, fullName, phoneno }) => {
(appliedCandidate[Title] = appliedCandidate[Title] || []).push({
fullName: fullName,
phoneno: phoneno
});
return appliedCandidate;
},
{}
);
console.log(list);
return (
<div>
{Object.keys(list).map((item, i) => {
return (
<ul>
{item}
<li key={i}>{item.fullName}</li>
</ul>
);
})}
</div>
);
Assuming your data looks like this:
const jobs = {
"design job": [
{
fullName: "Rakesh",
phoneno: "1111111111"
},
{
fullName: "test user",
phoneno: "9176837787"
}
],
"another job": [
{
fullName: "Rakesh",
phoneno: "1111111111"
},
{
fullName: "test user 2",
phoneno: "9176837787"
}
]
};
Here's the code that returns the JSX to display all the jobs, and for each job, all the candidates:
return Object.entries(jobs).map(([title, candidates]) => (
<ul>
<h3>{title}</h3>
{candidates.map((c, i) => (
<li key={i}>{c.fullName}</li>
))}
</ul>
));
function iMGroot() {
let appliedCandidates = [{
Title: 'title-1',
fullName: 'fullName-1',
phoneno: 'phoneno-1'
},
{
Title: 'title-11',
fullName: 'fullName-11',
phoneno: 'phoneno-11'
},
{
Title: 'title-12',
fullName: 'fullName-12',
phoneno: 'phoneno-12'
},
{
Title: 'title-13',
fullName: 'fullName-13',
phoneno: 'phoneno-13'
}, {
Title: 'title-14',
fullName: 'fullName-14',
phoneno: 'phoneno-14'
}
]
const list = appliedCandidates.reduce(
(appliedCandidate, {
Title,
fullName,
phoneno
}) => {
(appliedCandidate[Title] = appliedCandidate[Title] || []).push({
fullName: fullName,
phoneno: phoneno
});
return appliedCandidate;
}, {}
);
console.log(list);
return ( `<div> ${Object.keys(list).map((item, i) => {
return (
`<ul>
${list[item].map(lItem=>{
return `
<li>${lItem.fullName}</li>
<li>${lItem.phoneno}</li>
`
})}
</ul>`
)
})}</div>`
);
}
console.log(iMGroot())
PS: see the return statement of function iMGroot.
Since definition of appliedCandidates is missing, I've filled it in the above function.

Resources