Getting [object Object] instead of object in React - reactjs

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>
);

Related

How to get data from object inside array of FireStore db using react

how can i get this 'tags' data from firestore ?
i just want to get the spesific 'tags' from the 'blogs' object and push the tags to the array, in here i just have all of this tags data
const [blogs, setBlogs] = useState([]);
const [tags, setTags] = useState([]);
useEffect(() => {
const getBlogsData = async () => {
const blogRef = collection(db, 'blogs');
const blogs = await getDocs(blogRef);
setBlogs(blogs.docs.map((doc) => ({ id: doc.id, ...doc.data })))
blogs.docs.map((doc) => tags.push(...doc.get("tags")));
let newTags = [...new Set(tags)];
setTags(newTags);
};
getBlogsData();
}, []);
This is my data from firestore database
(2) [{…}, {…}]
0:
author: "jhon doe"
category: "Sports"
description: "Lorem Ipsum is simply dummy text ..."
id: "123"
imgUrl: "https:........"
tags: Array(2)
0: {id: 'sport', text: 'sport'}
1: {text: 'liverpool', id: 'liverpool'}
length: 2
[[Prototype]]: Array(0)
timestamp: nt {seconds: 1665798716, nanoseconds: 567000000}
title:
"Sport Match Liverpool"
trending: "yes"
userId: "1234"
[[Prototype]]: Object
and this is what i get from the 'tags' how can i get just spesific tags from the object inside array ?
(3) [{…}, {…}, {…}]
0: {text: 'sport', id: 'sport'}
1: {text: 'liverpool', id: 'liverpool'}
2: {id: 'fashion', text: 'fashion'}
length: 3
[[Prototype]]: Array(0)
thank you...

navigating results in changes of state in react after passing state to Link component

I'm making a purchase invoice app in react.
There are two pages in the app now.
One is a page to create new invoice which can be saved to database and exported to excel file. (Invoice.js)
The other is a page of a list of invoices each of them having modify/delete button. (Invoices.js)
When an invoice in the list's modify button is clicked, it links to the creation-page, and the invoice data, which is a state, are passed as parameter.
Without passing invoice data to the creation page, navigating had no problem at all.
However, after I put 'state' property to the Link component, the following error occurs.
Invoices.js:21
Uncaught TypeError: Cannot read properties of undefined (reading 'substring')
at Invoices.js:21:1
at Array.filter ()
at Invoices.js:21:1
at invokePassiveEffectCreate (react-dom.development.js:23487:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
at invokeGuardedCallback (react-dom.development.js:4056:1)
at flushPassiveEffectsImpl (react-dom.development.js:23574:1)
at unstable_runWithPriority (scheduler.development.js:468:1)
at runWithPriority$1 (react-dom.development.js:11276:1)
Here are my source codes
// App.js
const App = () => {
return (
<BrowserRouter>
<Container maxWidth="lg">
<NavBar />
<Routes>
<Route path="/" exact element={<Navigate to="/invoice/create" />} />
<Route path="/invoice/create" element={<Invoice />} />
<Route path="/invoice/view" element={<Invoices />} />
</Routes>
</Container>
</BrowserRouter>
);
};
// Invoices.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getInvoices } from '../../actions/invoices';
import InvoiceRow from './InvoiceRow';
const Invoices = () => {
const [month, setMonth] = React.useState(new Date().getMonth() + 1);
const invoices = useSelector((state) => state.invoices);
const dispatch = useDispatch();
const [invoicesCurrent, setInvoicesCurrent] = React.useState([]);
useEffect(() => {
dispatch(getInvoices());
}, [dispatch]);
useEffect(() => {
setInvoicesCurrent(invoices.filter((invoice) => Number(invoice.invoiceDate.substring(5, 7)) === month));
}, [invoices, month, dispatch]);
...
// Link component used: invoice is the one of invoice in invoices state
<Link to='/invoice/create'
state={{ ...invoice }}>
<Button>Modify</Button>
</Link>
// Invoice.js
const InvoiceComponent = () => {
const location = useLocation();
const invoice = location.state;
const [company, setCompany] = useState(invoice ? invoice.company : '');
const [employee, setEmployee] = useState(invoice ? invoice.employee : '');
const [invoiceDate, setInvoiceDate] = useState(invoice ? invoice.invoiceDate : new Date());
const [orderId, setOrderId] = useState(invoice ? invoice.orderId : '');
const [companyTel, setCompanyTel] = useState(invoice ? invoice.companyTel : '');
const [companyFax, setCompanyFax] = useState(invoice ? invoice.companyFax : '');
const items = useSelector((state) => state.items);
const dispatch = useDispatch();
useEffect(() => {
const last = document.getElementById(`row-${items.length - 1}-0`);
if (last != null) last.focus();
}, [items.length]);
useEffect(() => {
if (invoice) {
dispatch(updateItems(invoice.items));
}
}, [dispatch, invoice]);
...
I must share current app behavior.
When 'Modify' button clicked, creation page is loaded with invoice data.
Then navigating with 'Go back', 'Go forward', or clicking a link to any of both pages shows the upper error.
in the useEffect hook in Invoices.js that calls setInvoicesCurrent,
when I console.log(invoices), it is not an array of invoice, rather it is an array of other state(items), which was used in Invoice.js
Refreshing the page makes all thing reset.
Is there any guideline for managing redux store when navigating?
// console.log(invoices) in useEffect calling setInvoicesCurrent
// Normally opened: invoices (6) [{…}, {…}, {…}, {…}, {…},
{…}] 0: {_id: '1', company: 'cmp1', employee: 'e1', invoiceDate:
'2022-01-07T05:14:15.482Z', orderId: '', …} 1: {_id: '2', company:
'cmp2', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z',
orderId: '', …} 2: {_id: '3', company: 'comp3', employee: 'e1',
invoiceDate: '2022-01-07T05:14:15.482Z', orderId: '', …} 3: {_id:
'4', company: 'comp4', employee: 'e1', invoiceDate:
'2022-01-07T05:14:15.482Z', orderId: '', …} 4: {_id: '5', company:
'comp5', employee: 'e1', invoiceDate: '2022-01-07T05:14:15.482Z',
orderId: '', …} 5: {_id: '6', company: 'comp6', employee: 'e1',
invoiceDate: '2022-01-07T13:10:56.380Z', orderId: '', …} length: 6
[[Prototype]]: Array(0)
Each Array has the following data
0:
company: "cmp1"
companyFax: "1222222222" companyTel: "122331232" employee:
"e1" invoiceDate: "2022-01-07T05:14:15.482Z" items:
Array(2) 0: {name: 'item1', spec: 'spec1', qty: 1, price: 10000,
total: 10000, …} 1: {name: 'item2', spec: 'spec2', qty: 20,
price: 1000, total: 20000, …} length: 2 [[Prototype]]:
Array(0) modifiedOn: "2022-01-07T05:25:14.771Z" orderId:
""
__v: 0
_id: "1"
// console.log(invoices) when ERROR occurs: invoices (6)
[Array(2), Array(2), Array(2), Array(2), Array(2), Array(2)] 0:
Array(2) 0: {name: 'item1', spec: 'spec1', qty: 1, price:
10000, total: 10000, …} 1: {name: 'item2', spec: 'spec2', qty:
20, price: 1000, total: 20000, …} length: 2
[[Prototype]]: Array(0) 1: Array(2) 0: {name: 'item1',
spec: 'spec1', qty: 1, price: 10000, total: 10000, …} 1: {name:
'item2', spec: 'spec2', qty: 20, price: 1000, total: 20000, …}
length: 2 [[Prototype]]: Array(0) 2: (2) [{…}, {…}]
3: (2) [{…}, {…}] 4: (2) [{…}, {…}] 5: (2) [{…}, {…}]
length: 6 [[Prototype]]: Array(0)
You should not destructure the array to an object, It creates an object.
use like below
// Invoices.js
<Link to="/invoice/create" state={{ invoice }}>
<Button>Modify</Button>
</Link>;
// Invoice.js
const { invoice } = location.state;
Note:
const a = [1,2,3];
console.log({...a}); // {0: 1, 1: 2, 2: 3}

Map array from another api endpoint and pass through prop of React child component

I need to pass responses from two APIs, i.e. hobbies and person API, to my child component. So I am able to map() the child component and show the data in a list.
The response from person api:
{[
0: {id: 01, name: {…}, familyName: {…}, phone: 0 …}
1: {id: 02, name: {…}, familyName: {…}, phone: 0 …}
2: {id: 03, name: {…}, familyName: {…}, phone: 0 …}
3: {id: 04, name: {…}, familyName: {…}, phone: 0 …}
4: {id: 05, name: {…}, familyName: {…}, phone: 0 …}
5: {id: 06, name: {…}, familyName: {…}, phone: 0 …}
6: {id: 07, name: {…}, familyName: {…}, phone: 0 …}
]
}
The response from hobbies api:
{ data: {
name: "Test name"
hobbies: (2) [{…}, {…}]
userId: "test"
_id: "4767647478"
}
}
The component:
const PersonList = () => {
const [loading, setLoading] = useState(false);
const [persons, setPersons] = useState<Person[]>([]);
const [hobbies, setHobbies] = useState<Hobbies[]>([]);
const urls = [
"https://person-api",
"https://hobbies-api",
];
const getData = async () => {
setLoading(true);
const [result1, result2] = await Promise.all(
urls.map((url) => fetch(url).then((res) => res.json()))
);
setLoading(false);
setPersons(result1);
setHobbies(result2);
};
useEffect(() => {
getData();
}, []);
return (
<div>
<div>
{persons.map((person) => {
return (
<PersonCard
key={person.id}
name={person.name}
/>
);
})}
</div>
</div>
);
};
export default PersonList;
The above code works fine and renders a list of names of the persons. But how do I map() and pass the hobbies (from different api response) with a prop e.g. hobbies through my child component,like below?
<PersonCard
key={person.id}
name={person.name}
hobbies={hobby.name}
/>

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);

How to properly map results from api fetch react

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].

Resources