React is mapping duplicate posts
like this
Ideally im just looking to map the likes array.
{myLikes.map(like =>
)}
within the posts, i don't want duplicates posts. How would i achieve that ?
PostList.js
render(){
const {posts, myLikes} = this.props;
return (
<div>
{posts.map(post => (
<div>
{myLikes.map(like =>
<Paper key={post.id} style={Styles.myPaper}>
<PostItem
myLikes={like}
myTitle={this.state.title}
editChange={this.onChange}
editForm={this.formEditing}
isEditing={this.props.isEditingId === post.id}
removePost={this.removePost}
{...post}
// {...like}
/>
</Paper>
)}
</div>
))}
</div>
)
}
}
const mapStateToProps = (state) => ({
isEditingId: state.post.isEditingId,
myLikes: state.post.likes // reducer likes
})
Posts
Likes
This is actually what you told React to do, without realizing it.
I'm assuming that myLikes is an array of numbers, in this case [32, 15].
Your code says (in pseudocode form):
for each post p
for each like l
render the post p with like l
That gives you 2 * 2 = 4 copies.
this is due to nested maps in the PostList component,
you can merge the mylikes and post arrays first and then use map
How to merge multiple arrays
this is how it will work
const results = _.merge(myLikes, posts);
return (
<div>
{results.map(result => (
<Paper key={result.id} style={Styles.myPaper}>
<PostItem
myLikes={result.like}
myTitle={this.state.title}
editChange={this.onChange}
editForm={this.formEditing}
isEditing={this.props.isEditingId === post.id}
removePost={this.removePost}
/>
</Paper>
))}
</div>
);
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 an array of objects and I need the keys and values to be editable, I was given this approach : https://codesandbox.io/s/silly-gagarin-j8cfi?file=/src/App.js
But as you can see, the inputs are all empty.
I have tried using defualtValue but that will cause problems later I believe. The aim of this is to eventually compare these values to a database later on.
Please can someone take a look at the sandbox I linked above and help me out?
You need to use Object.entries which will give you access to both the key and value of each property. Your example was not working because you were trying to destructure Object.values as an object when it returns an array.
See my working code below:
https://codesandbox.io/s/inspiring-swirles-208cm?file=/src/App.js
export default function App() {
const [data, setData] = useState(baseData);
const updateValue = (index) => (e) => {
setData((prev) => {
const copiedData = [...prev];
copiedData[index][e.target.name] = e.target.value;
return copiedData;
});
};
return (
<>
<div>
{data.map((item, index) => (
<div key={item.id}>
{Object.entries(item).map(([key, value]) => (
<input
name={key}
type="text"
id={item.id}
key={item.id}
value={value}
onChange={updateValue(index)}
/>
))}
</div>
))}
</div>
</>
);
}
This is my second day first day learning react and I came across problem that I could solve in a better way but I don't know how it is done in React.
import ExpenseItem from './ExpenseItem';
import './Expenses.css';
function Expenses(props) {
const { items } = props;
// const html = items
// .map(el => {
// return `
// <ExpenseItem
// title={${el.title}}
// amount={${el.amount}}
// date={${el.date}}
// ></ExpenseItem>`;
// })
// .join('');
// console.log(html);
return (
<div className="expenses">
<ExpenseItem
title={items[0].title}
amount={items[0].amount}
date={items[0].date}
/>
<ExpenseItem
title={items[1].title}
amount={items[1].amount}
date={items[1].date}
/>
<ExpenseItem
title={items[2].title}
amount={items[2].amount}
date={items[2].date}
/>
<ExpenseItem
title={items[3].title}
amount={items[3].amount}
date={items[3].date}
/>
</div>
);
}
export default Expenses;
So this is the thing. I am hardcoding 4 custom components because that is the length of props.items array.
Code that I commented out will create template literal based on length of items array, so for each item I will have created component. That is all fine but here comes the problem.
I don't know how to append that to the div with class name of "expenses".
That is problem I have.
Thank you in advance for answers.
You can map items array in return and it will render ExpenseItem for all items in array.
Try something like this:-
import ExpenseItem from './ExpenseItem';
import './Expenses.css';
function Expenses(props) {
const { items } = props;
return (
<div className="expenses">
{items.map((item, index) => (
<ExpenseItem
key={item.id || index}
title={item.title}
amount={item.amount}
date={item.date}
/>
))}
</div>
);
}
export default Expenses;
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;
});
What I want to do, using map, is pretty plain.
I want to call this:
<Striper size={3} text={"Hey everybody!"}/>
To get this:
<>
<Stripe>
<Stripe>
<Stripe>
Hey everybody!
</Stripe>
</Stripe>
</Stripe>
</>
I tried this way, but it fails:
const Striper = (props) => {
const contentTop=props.sizer.map((item)=> <Stripe>)
const contentBottom=props.sizer.map((item)=> </Stripe>)
return (
<div>
{contentTop}
{contentBottom}
</div>
)
}
Basically only this works (which isn't what I want):
const contentTop = props.sizer.map((item)=> <Stripe></Stripe>)
How could I get what I want?
The solution ended up being really simple (thank you, Emile): use .reduce.
As it says in the documentation about reduce, it's really useful when you need only one thing returned. And that's what I needed.
As I said in a comment:
What I want to return from <App size={2} text="Hello"/> is really
<Stripe><Stripe>Hello</Stripe></Stripe>, but because I have to
return a whole object, the closest I can come with map is
<Stripe>Hello</Stripe><Stripe>Hello</Stripe>.
So instead, use reduce.
This is the solution, verified to work. (Note: I'm being somewhat handwavey about size={3} when it's actually an array, because I know how to do that stuff, it isn't my question but you can see my implementation in the answer below).
const Striper = (props) => {
const content = props.sizer.reduce(
(total, currentValue) => <Stripe color={props.colors}>{total}</Stripe>
)
return (
<div>
{content}
</div>
)
}
And as it's actually called:
const arr = Array(6).fill("this is my text!");
return (
<div>
<Striper sizer={arr} colors={colours}/>
</div>
);
I guess you can achieve something like with this approach:
import React from 'react';
import { render } from 'react-dom';
const Stripe = () => <span> – </span>
const App = ({ size, text }) => {
const arrFromNum = Array.from(Array(size), (x, i) => i + 1)
return (
<React.Fragment>
{arrFromNum.map(x => <Stripe />)}
{text}
{arrFromNum.map(x => <Stripe />)}
</React.Fragment>
)
}
render(<App size={4} text="Hello" />, document.getElementById('root'));
Does this answer your question?
Here's one possible way of many different possibilities based on your scenario:
<Striper size={3} text={"Hey everybody!"}/>
export default ({ size, text }) => <><Stripe size={size} /> {text} <Stripe size={size} /></>;
export default ({ size }) => <>{ Array(size).fill().map(_ => <h3>Stripe!</h3>) }</>;
https://stackblitz.com/edit/react-tnqv2k