I have this long-winded component which is passing many props. Is there a dryer way of passing this component to child?
Thanks.
let products;
if (!this.state.loading) {
products = this.state.products.map(product => (
<Product
description={product.description}
title={product.title}
originalRetailPrice={product.original_retail_price.formatted_value}
retailPrice={product.retail_price.formatted_value}
priceValue={product.retail_price.value}
discounted={product.discount}
imageURL={product.cover_image_url}
key={product.uuid}
uuid={product.uuid}
onClick={this.addToBagHandler}
/>
));
}
These are properties returned from an api call.
You just pass the whole product instead
let products;
if (!this.state.loading) {
products = this.state.products.map(product => (
<Product
product={product}
onClick={this.addToBagHandler}
/>
));
}
And inside Product you can access them like this:
const { description, title, discount } = this.props.product
You can destructure like this
let products;
if (!this.state.loading) {
products = this.state.products.map(({
description,title, original_retail_price,
retail_price, retail_price,discount,cover_image_url,
uuid}) =>
<Product
description={description}
title={title}
originalRetailPrice={original_retail_price.formatted_value}
retailPrice={retail_price.formatted_value}
priceValue={retail_price.value}
discounted={discount}
imageURL={cover_image_url}
key={uuid}
uuid={uuid}
onClick={this.addToBagHandler}/>
)}
Related
Check the render method of `Category`. See https://reactjs.org/link/warning-keys for more information.
at FoodCard (http://localhost:3000/static/js/bundle.js:966:5)
at Category (http://localhost:3000/static/js/bundle.js:2829:66)
My error might be generated from this snippet of code but I am not sure.
const Category = () =>{
const {category} = useParams();
const {categoriesMap} = useContext(CategoriesContext);
const[products, setProducts] = useState([categoriesMap[category]]);
useEffect(()=>{
setProducts(categoriesMap[category]);
}, [category, categoriesMap])
return (
<Fragment>
<h2 className='category-title'>{category.toUpperCase()}</h2>
<div className='category-container'>
{products &&
products
.map((food) => (
<FoodCard key={food.id} food={food} />
))}
</div>
</Fragment>
);
};
export default Category;
your issue seems to come from key={food.id}
you should check out your food.id values. There is probably two identical value in your dataset
I have this response object from an api, and I want to loop it and render it as if it was a normal array, how can I render tshirt, jeans and furniture? I will not like to render the value of sneakers, Any suggestion?
const items = {
tshirt: "Model TS",
jeans: "ModelXW",
sneakers: "indcdsc54",
furniture: "Table31S"
};
{Object.keys(items).map=>{i =>
<Card>
{items[key]}
</Card>
}
}
Try this one implementation line:
{Object.entries(items).filter(v => v[0] !== 'sneakers').map((v, idx) => <Card key={idx}>v[1]</Card>)}
You can read properties of an object using dynamic key: objectName[keyName]:
{
Object.keys(items).map(key => <Card key={key}>{items[key]}</Card>)
}
and to filter out sneakers:
{Object.keys(items).filter(key => key !== 'sneakers').map((key) => (
<Card key={key}>{items[key]}</Card>
))}
Instead of multiple loops, add an if condition to your code:
Object.keys(items).map(key => {
if (key != 'sneakers') {
return(<Card>{items[key]}</Card>);
}
});
We can use destructuring and it is definitely more readable.
const { sneakers, ...rest } = items;
Object.keys(rest).map((item, id) => {
<Card key={id}>
{item}
</Card>
}
);
Say there are nested components, where data is passed from top to root, but only root component needs the data, how to deal with this more efficiently? Check the following example:
const Myform = () => {
return (
<Section title={'Nested component'} />
)
}
const Section = ({title}) => {
return (
<Card title={title} />
)
}
const Card = ({title}) => {
return (
<Title title={title} />
)
}
const Title = ({title}) => {
return (
<h2>{title}</h2>
)
}
Myform passes title data to Section, then passes to Card, then passes to root component Title, where data is only needed in Title component. The 2 middle components only pass data. I can see two problems:
Each middle component needs to accept title, but has no use of title at all;
If more middle components are needed, each of them needs to repeat the same process.
In fact only Myform and Title need to know the data. Is there a more efficient way to deal with this kind of scenario?
You can create the Title component at the top and pass that down instead of the props. This is what Facebook recommends here in their docs on Composition vs Inheritance
EG:
const Myform = () => {
return (
<Section Title={<Title title='Nested component' />} />
)
}
const Section = ({Title}) => {
return (
<Card Title={Title} />
)
}
const Card = ({Title}) => {
return (
<Title />
)
}
const Title = ({title}) => {
return (
<h2>{title}</h2>
)
}
In this example with so many levels it doesn't work that great - in that case the Context API might be better
I am working a project and want to be able to send data from a component to its props.children component. I think this is done using render props in class components but I don't know how to implement it in a functional one. Here is an extremely simplified version of something I am trying to accomplish. I want to render different things in the Child component depending on what "edit" is set to in Parent.
function Parent({ children }) {
const [edit, setEdit] = useState(false);
return (
<div>
{"blah blah blah..."}
<button onClick={()=>{setEdit(!edit)}}>Click</button>
{children}
</div>
);
}
function Child() {
if (edit === true) {
return (
<Parent>
{"Edit is True"}
</Parent>
);
}
return (
<Parent>
{"Edit is False"}
</Parent>
);
}
You have to generate children components by cloning elements manually.
How to pass props to {this.props.children}
Is this what you need? You can share states to children
const Parent = () => {
const [edit, setEdit] = useState(true);
return (
<>
<div>Hello</div>
<Child edit={edit} />
</>
);
};
const Child = params => {
return params.edit? (
<div>Do something if true</div>
):
(
<div>Do something if false</div>
)
};
I have my products components which simply display products, price and description
const Product = (props) =>{
return(
<div>
<p>Price: {props.price} </p>
<p>Name: {props.name}</p>
<p>Description: {props.desc}</p>
</div>
)
}
Which is rendered by the App component which loops thru the data in productsData and renders a product component for each index in the array.
class App extends React.Component {
render() {
const products = productsData.map(product => {
return <Product key={product.id} price={product.price}
name={product.name} desc={product.description} />
})
return (
<div>
{products}
</div>
);
}
}
However, for the sake of learning purposes, I am trying to figure out how I am able to loop thru this array of products components (rendered in App) to only display, for example, prices that are greater than 10 or descriptions that are longer than 10 characters, for example.
productsData looks something like this
const productsData = [
{
id: "1",
name: "Pencil",
price: 1,
description: "Perfect for those who can't remember things! 5/5 Highly recommend."
},
I am assuming I need to use the .filter method inside the products component, but I can't seem to figure out where. I keep getting errors or undefined.
Could someone clear this up, how one would iterate thru components nested inside other components?
Try this:
const products = productsData.filter(product => (
product.price > 10 || product.description.length > 10
)).map(p => (
<Product key={p.id} price={p.price}
name={p.name} desc={p.description}
/>
))
Chaining methods filter with map allows you get the desired result.
Read more here about filter: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
You can add a condition in .map, if condition matches then return the Product else return null.
const products = productsData.map((product) => {
if (product.price > 10 || product.description.length > 10)
return (
<Product
key={product.id}
price={product.price}
name={product.name}
desc={product.description}
/>
);
return null;
});