how to access children props in React - javascript

Really sorry, I know this has been posted before but I just didn't understand how the answers related to my problem. I'm very new to react and need a bit more help than I could find.
My app project has reviews like this;
const restaurantData = [
{
id: 1,
restaurantName: "Restaurant 1",
address: "4, Dolphin Way, Swansea SA10 5BZ",
lat: 48.8737815,
long: 2.3501649,
ratings: [{ ratingID: 1, stars: 2, comment: "Terrible service, Yikes!" }],
},
];
And I have accessed the data no problem like this;
function RestaurantItem({ restaurant }) {
return (
<div className="restaurantItem" id={restaurant.id}>
<h2 className="AsideHeader">{restaurant.restaurantName}</h2>
<p className="AsideAddress">{restaurant.address} </p>
</div>
);
}
I would basically like to access the review data specifically by doing something like this;
<div>
<p>{restaurant.ratings.stars} STAR : </p> {restaurant.ratings.comment}
</div>
But I am not having any luck. Can someone explain what I am doing wrong and how to address it ? Or even what else I would call this to look up the solution?
Thank You !

ratings is an array, so you can't access the data as ratings.stars or ratings.comment.
An approach would be to use map to iterate through the ratings and display all of them for that specific restaurant.
<div>
{restaurant.ratings.map((rating) => (
<p key={rating.ratingID}>{`${rating.stars} STAR: ${rating.comment}`}</p>
))}
</div>

Inside your const restaurantData the ratings is an array. If there is only 1 rating then remove the array:
ratings: { ratingID: 1, stars: 2, comment: "Terrible service, Yikes!" }
If there will be multiple ratings then use .map to loop every single one.
{restaurant.ratings.map((rating) => (
<div key={rating.ratingID}>
<p>{rating.stars} STAR : </p> {rating.comment}
</div>
))}

Since restaurant.ratings is a list you can't display it just like a string.
You could display them like this:
<div>
{restaurant.ratings.map((rating, index) => (
<p key={"rating-" + rating.ratingID}>
{rating.stars + " STAR : " + reating.comment}
</p>
))}
</div>
The map method of the list iterates over every element and returns each as "described" by the anonymous method as a JSX Element.

You call props on array, but you need call prop on element of array.
If the ratings property always has one element, then you can write it like this, but it will be a crutch
function RestaurantItem({ restaurant }) {
return (
<div className="restaurantItem" id={restaurant.id}>
<h2 className="AsideHeader">{restaurant.restaurantName}</h2>
<p className="AsideAddress">{restaurant.address} </p>
</div>
<div>
<p>{restaurant.ratings[0].stars} STAR : </p> {restaurant.ratings[0].comment}
</div>
);
}
#lich reported correctly, to work with an array, you must use the map method
using reactjs list look here
js arrays

Related

Properly filter an array inside other array in reactjs

Hello I am trying react for the first time and I am having some trouble with my filter function.
Here's the code:
So this is my render method in my component:
const categoryFilter = this.state.appItems.filter(item =>
item.categories.filter(str => {
return str.includes(active);
})
);
const appList = categoryFilter.map(appItem => (
<AppItem appItem={appItem} key={appItem.id}></AppItem>
));
return (
<React.Fragment>
<div className="flex-container">
<NavCategories
categories={this.state.categories}
onClick={this.handleClick}
active={active}
/>
<section className="apps-list">
<header>
<input type="text" placeholder="Search by App" />
</header>
<ul>{appList}</ul>
</section>
</div>
</React.Fragment>
);
this.state.appItems is an array coming from a json file, here's a snippet:
[ {
"id": "12312",
"name": "Test",
"description": "test.",
"categories": ["Voice", "Delivery", "Optimization"],
"subscriptions": [
{
"name": "Trial",
"price": 0
},
{
"name": "Professional",
"price": 3500
}
]
},]
Active is a string to manage active class items on another component.
Everything renders correctly, but it is never filtered even though the active state is changing everytime.
I have tried multiple ways, but this Filter method is getting me confused a lot because I want to filter an array thats inside another array and want to filter the whole AppItem array.
If anyone could explain/give me some tips I would love it. Thanks in advance :)
Array.filter() returns a new array with the filtered elements in it. So your inner filter will always return an array of at least zero elements, which evaluates to a truthy value, and your outer filter will just include every element in the original array.
Just switch your inner filter to be an Array.includes() instead, which will return true or false.
const categoryFilter = this.state.appItems.filter(item =>
item.categories.includes(active)
);

How to iterate through an array of objects from json in React.js

I am trying to loop through an array of objects in an external json file using the map function. The loop succeeds but I am not sure how to access the object properties. See below.
I am using object.keys(obj).map() but cannot get access to the individual properties. Map keeps outputting the array index numbers.
This is my data I want to iterate through.
[
{
"id" : "12345",
"customer" : "BMW",
},
{
"id" : "45678",
"customer" : "Ford",
},
{
"id" : "78901",
"customer" : "Google",
}
]
I have a state hook that the data will be saved to
const [accountData, setAccountData] = useState('');
The function below gets the data from the external json file and sets the state with it.
axios.get('./data/account-info.json')
.then((response) => {
//set state
setAccountData(response.data);
})
.catch((error) => {
console.log(error);
});
I iterate through the state object with a map function
Object.keys(accountData).map((id,customer) => {
return(
<div>
<p>ID: {id}</p>
<p>Name: {customer}</p>
</div>
)
})
The output keeps printing out the index numbers instead of the appropriate values
//outputted elements
<div>
<p>ID: 0</p>
<p>Name: 0</p>
</div>
<div>
<p>ID: 1</p>
<p>Name: 1</p>
</div>
<div>
<p>ID: 2</p>
<p>Name: 2</p>
</div>
Can you please tell me what I am doing wrong here? I know it has to be something simple.
You can iterate accountData directly, as it's an array.
Each item will be an object, so you need to destructure as you see below.
(you don't need to but that's was the intention I perceived from your code)
And also you need to add a key to each element, to notify React how to keep track of elements.
// 👇 destrcuture the properties
accountData.map(({ id,customer }) => {
return(
{/* 👇 make sure to add keys here too */}
<div key={id}>
<p>ID: {id}</p>
<p>Name: {customer}</p>
</div>
)
})
-- Reply to the [COMMENT] --
so whenever I remove the object.keys() it throws this error at me TypeError: accountData.map is not a function
Would you double check if response.data is as what you mentioned in the post?
If you run the code below, it will correctly print id & customer array.
let accountData = [
{
"id" : "12345",
"customer" : "BMW",
},
{
"id" : "45678",
"customer" : "Ford",
},
{
"id" : "78901",
"customer" : "Google",
}
]
accountData.map(({id, customer}) => console.log(id, customer))
try this
Object.keys(accountData).map((e) => {
return(
ID: {e.id}
Name: {e.customer}
)
})
Object.keys(accountData) will give you the keys of the array, ex 0,1,2. just do accountData.map to iterate through the array instead.
accountData.map(customer => {
return(
<div
key={ customer.id }
>
<p>ID: { customer.id }</p>
<p>Name: { customer.customer }</p>
</div>
)
})
Object.keys function returns the array of its keys. For array object, its keys are its indices. So in case of your accountData, Object.keys(accountData) returns [ '0', '1', '2' ].
If you still want to use Object.keys function, you can do like this.
Object.keys(accountData).map(key => (
<div key={accountData[key].id}>
<p>ID: {accountData[key].id}</p>
<p>Name: {accountData[key].customer}</p>
</div>
));
But in case of an array, it would be better to apply map function directly to it.
accountData.map(account => (
<div key={account.id}>
<p>ID: {account.id}</p>
<p>Name: {account.customer}</p>
</div>
));
That's all.

Error: Objects are not valid as a React child (found: object with keys..........)

I am trying to loop through the array of objects. Value of this.state.saveFriendTag or this.props.userTags on console is:
State in constructor is:
saveFriendTag: this.props.userTags? this.props.userTags: [],
Code is:
if(this.props.cardData){
if (this.state.saveFriendTag.length == 1) {
taggedFriendsBlue = this.state.saveFriendTag.map((item, index) => {
console.log(item,"item");
return (
<span className="displayedName blue" key={index}>{item.firstname}</span>
)
})
}
This is in return and taggedFriendsBlue is defined in render:
<div className="pCard_contentContainer ">
<textarea id="pcardTextarea" type="text" placeholder="Write Description here..." value={this.state.Description} onChange={this.textareaExpansion.bind(this)}></textarea>
<If test={this.state.tagDone == true || this.state.saveFriendTag.length>0}>
<div className="displayNames disp_inliFl">
<span className="pcard_WithOne">-With</span>
<div className="disp_inliFl">
{taggedFriendsBlue}
</div>
</div>
</If>
</div>
Can anybody tell the reason for this console error? How to correct it?
It looks like the issue is that you are using Object.keys on an array. You can remove that and just use .map directly.
Additionally, you need to specify a key for the span.
<span key={item.id} ... />
const array = [
{
firstName: "test",
lastName: "test2"
}
];
console.log(Object.keys(array));
As you can see from the code snippet, using Object.keys on an array will result in the index being passed on each iteration of the map function, instead of the object as you intend.

cannot get the parent property this property when I have two inner loop

I have a complicated scenario which I am really confused how to deal with it.
I have an array as follows:
stories=[
{
"categ": "politics",
"arr": [{
"t": 1
}, {
"t": 2
}, {
"t": 3
}]
},
{
"categ": "Business",
"arr": [{
"t": 1
}, {
"t": 2
}, {
"t": 3
}]
}
]
As you can see this array has another array inside it and depending on what is executed I need to loop through the first array and find the appropriate array inside the first array. So for instance if I want to get the array related to business category I need to loop through the first array and choose the array related to business. To do so I have the following code:
<div className="row">
{
this.props.stories.map((item,i)=> <Story key={i} position={i} story={item} ></Story>)
}
</div>
So you can see that with map I am able to loop through the first array. Now considering that by using this.props.categ I can access the category that I want. so I have to change my code to sth like below:
<div className="row" >
{
this.props.stories.map(function(snippet){
if(snippet.categ==="politics"){
return(
snippet.arr.map((item,i)=> <Story key={i} position={i} story={item} ></Story>)
);
}
})
}
</div>
But in the above code "politics" is hard coded and should be replaced with this.props.categ. However as soon as I replace that I get the error saying
Uncaught TypeError: Cannot read property 'props' of undefined
which totally make sense since I am loosing the parent this since I do not use es6 fat arrow. Now how can make this work?
You can bind the outer map function like
<div className="row" >
{
this.props.stories.map(function(snippet){
if(snippet.categ===this.props.categ){
return(
{snippet.arr.map((item,i)=> <Story key={i} position={i} story={item} ></Story>})
);
}
}.bind(this))
}
</div>
This will allow you map function to refer to the outer context where prop is available. Also you forgot to include your inner map function inside {}
Other option is to use the arrow function
<div className="row" >
{
this.props.stories.map(snippet) => {
if(snippet.categ===this.props.categ){
return(
{snippet.arr.map((item,i)=> <Story key={i} position={i} story={item} ></Story>})
);
}
}.bind(this))
}
</div>
Save the this to that before entering the function.
Then use that.props.categ to refer to the outer this.
If that makes any sense :D
Something like so:
render(){
// place here
// at the top of render function
// but outside the return
var that = this;
return (
{something.map(function(snippet){
if (snippet.categ === that.props.categ){
// do things here
}
})}
);
}

Cart not adding correct item in React.js

I'm learning React.js (and I'm a beginner at JavaScript) and having some difficulty getting my addToCart function working properly. I've managed to get all my products to display but adding to cart on any of them only adds the first item, and once that item is out of stock then all the items go out of stock.
I'm sure I'm missing something obvious but would really appreciate some more experienced eyes on my code please.
Github repo for this app
Below are my FluxProduct.react.js product components:
var React = require('react');
var FluxCartActions = require('../actions/FluxCartActions');
var FluxProduct = React.createClass({
addToCart: function(event){
var id = this.props.selected.id;
var update = {
name: this.props.product.name,
category: this.props.selected.category,
price: this.props.selected.price
}
FluxCartActions.addToCart(id, update);
FluxCartActions.updateCartVisible(true);
},
render: function() {
var self = this;
var products = this.props.product;
var stockAvailable = (this.props.selected.id in this.props.cartitems) ? this.props.selected.stock - this.props.cartitems[this.props.selected.id].quantity : this.props.selected.stock;
return (
<ul>
{Object.keys(products).map(function(product){
return (
<li key={product}>
<div className="flux-product">
<img src={'img/' + products[product].image}/>
<div className="flux-product-detail">
<h1 className="name">{products[product].name}</h1>
<p className="category">{products[product].category}</p>
<p className="description">{products[product].description}</p>
<p className="price">Price: ${products[product].price}</p>
<button type="button" onClick={self.addToCart} disabled={stockAvailable > 0 ? '' : 'disabled'}>
{stockAvailable > 0 ? 'Add To Cart' : 'Sold Out'}
</button>
</div>
</div>
</li>
)
})}
</ul>
);
},
});
module.exports = FluxProduct;
Relevant FluxCartApp.react.js components:
render: function(){
return (
<div className="flux-cart-app">
<FluxCart products={this.state.cartItems} count={this.state.cartCount} total={this.state.cartTotal} visible={this.state.cartVisible} />
<FluxProduct product={this.state.product} cartitems={this.state.cartItems} selected={this.state.selectedProduct} />
</div>
);
},
Relevant cart actions:
selectProduct: function(index){
AppDispatcher.handleAction({
actionType: FluxCartConstants.SELECT_PRODUCT,
data: index
})
},
addToCart: function(id, update){
AppDispatcher.handleAction({
actionType: FluxCartConstants.CART_ADD,
id: id,
update: update
})
},
Sorry but I'm not sure what further relevant code needs to be pasted, if anyone has any advice I'd be grateful.
You're accessing the products variable from inside your map function, when instead you should be using the product parameter that is passed to it. Additionally, why map on the keys of products, just us the products as an array:
<ul>
{products.map(function(product){
return (
<li key={product}>
<div className="flux-product">
<img src={'img/' + product.image}/>
<div className="flux-product-detail">
<h1 className="name">{product.name}</h1>
<p className="category">{product.category}</p>
<p className="description">{product.description}</p>
<p className="price">Price: ${product.price}</p>
<button type="button" onClick={self.addToCart.bind(null, product.id)} disabled={stockAvailable > 0 ? '' : 'disabled'}>
{stockAvailable > 0 ? 'Add To Cart' : 'Sold Out'}
</button>
</div>
</div>
</li>
)
})}
</ul>
Notice that I've used bind to pass the product ID through to addToCart as well, and this lets us use it like this, with the bound ID passed as the first argument:
addToCart: function(id, event){
var update = {
name: this.props.product.name,
category: this.props.selected.category,
price: this.props.selected.price
}
FluxCartActions.addToCart(id, update);
FluxCartActions.updateCartVisible(true);
}
You may also be interested in the answer "JavaScript variable binding and loop" which may have been a contributing factor in your problem and often catches out JavaScript newcomers.

Categories