Limit number of results in object.map [duplicate] - javascript

This question already has answers here:
Limit items in a .map loop
(5 answers)
Closed 3 years ago.
I'm importing the spaces object. I only want to render 3 of the Card components which requires attributes from spaces. Imagine a 'featured' section on a website displaying only a few items from a larger list.
With the below code I'm currently rendering all of the results instead of 3, am I using the correct methods? And if so, is the order wrong?
<div className="row">
{spaces.map(item => {
for (var i = 0; i < 2; i++) {
return (
<div className="col-sm-12 col-md-6 col-lg-4" key={item.id}>
<Card
town={item.town}
name={item.name}
net={item.net}
day={item.day}
night={item.night}
dog={item.dog}
parking={item.parking}
image={item.image}
/>
</div>
)
}
})}
</div>

spaces.map will iterate over all elements in spaces and produce a new array, with a new value for each existing item.
The loop inside the map callback is useless since you are returning in the first iteration, terminating the loop immediately.
If you only want to get the first 3 spaces, then you can .slice the array:
<div className="row">
{spaces.slice(0,3).map(item => {
return (
<div className="col-sm-12 col-md-6 col-lg-4" key={item.id}>
<Card
town={item.town}
name={item.name}
net={item.net}
day={item.day}
night={item.night}
dog={item.dog}
parking={item.parking}
image={item.image}
/>
</div>
)
})}
</div>

You can do like below
<div className="row">
{spaces.map((item,index) => {
if(index < 3){
return (
<div className="col-sm-12 col-md-6 col-lg-4" key={item.id}>
<Card
town={item.town}
name={item.name}
net={item.net}
day={item.day}
night={item.night}
dog={item.dog}
parking={item.parking}
image={item.image}
/>
</div>
)
}
})}
</div>

Related

Mapping over 2 arrays

I have 2 arrays of objects: meeting and room and a Card component with some fields to be completed by them.
I tried to map over the arrays in order to access the elements from both of them at the same time but it returns the Card component six times(the number of the elements in the array of Room)
<div className="topCards">
{room.map((dataObj) => {
return (
<div>
{meeting.map((meetObject) => {
return (
<div className="item">
<Card3
className="card3"
teamName={meetObject.name}
roomName={dataObj.name}
time={dataObj.time}
data={dataObj.data}
capacity={dataObj.capacity}
/>
</div>
);
})}
</div>
);
})}
</div>
So, my question is how can I return the Card element with elements from both cards
What let you think that it would work like that?
Just use the index parameter of Array.prototype.map
<div className="topCards">
<div>
{meeting.map((meetObject, i) => {
return (
<div className="item">
<Card3
className="card3"
teamName={meetObject.name}
roomName={dataObj[i].name}
time={dataObj[i].time}
data={dataObj[i].data}
capacity={dataObj[i].capacity}
/>
</div>
);
})}
</div>
</div>

React Nested Foreach on Return

Trying to use nested foreach in React.
But not working at all;
return (
{category.map((item, i) => (
<div className="col-sm-12">
<h5>{item.title}</h5>
</div>
item.data.map((it, iv) => (
<div class="col-6">
<ProductCard {...it} />
</div>
))
))}
)
You are using .map higher order function
you need to wrap in in fragment so React Will know that it's a JSX or wrap it on div
Introduction to JSX
Learn Fragment React
return (
<>
{category.map((item, i) => (
<div className="col-sm-12">
<h5>{item.title}</h5>
</div>
item.data.map((it, iv) => (
<div class="col-6">
<ProductCard {...it} />
</div>
))
))}
</>
)
if you want to render nested array maybe it will work
return (
<> // Put Wrapper
{category.map((item, i) => (
<> // put an empty fragment to contain title div and another map
<div key={i} className="col-sm-12"> // dont forget to put key props
<h5>{item.title}</h5>
</div>
{item.data.map((it, iv) => ( // wrap another map on '{}' because it inside jsx
<div key={iv} class="col-6"> // dont forget to put key props
<ProductCard {...it} />
</div>
)}
</>
)}
</>
)
you can also change <> to div or any if you want to style it. And dont put // comment on jsx, it just my mark to explain this code

Check if index of iteration is divisible by 2

I know I can check this with pure Js index % 2 === 0 however when
I'm attempting to use it in React which should work I get errors from linter:
<div className="columns">
{posts.map((item,index) => (
<>
<div className="column is-half">
<Card {...item} />
</div>
{index % 2 === 0 && </div><div className="columns">}
</>
))}
What am I doing wrong ?
Edit:
<div className="columns">
{posts.map((item,index) => (
<div className="column is-half">
<Card {...item} />
</div>
{index % 2 === 0 && (
</div><div className="columns">
)}
))}
The above still throws syntax error. I've checked brackets and logic is correct too.
I think you have invalid JSX syntax and this is your issue.
You cannot open a div element without setting the closing tag directly or setting the closing tag in a loop. This is invalid syntax, even if it would fit from the logic...
Try this:
<div className="columns">
{
posts.map((item,index) => (
<>
<div className="column is-half">
<Card {...item} />
</div>
{
index % 2 === 0 &&
<div className="columns">
</div>
}
</>
))
}
</div>

Cards inside the grid-container: each child in a list should have a unique "key" prop

What I`m doing wrong?It also says: "Check the render method of Card" , which is here:
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={pokemon.id} pokemon={pokemon} />
})}
</div>
Card component itself:
function Card({ pokemon }) {
return (
<div className="card">
<div className="card__image">
<img src={pokemon.sprites.front_default} alt="Pokemon" />
</div>
<div className="card__name">
{pokemon.name}
</div>
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type" style={{backgroundColor: typeColors[type.type.name]}}>
{type.type.name}
</div>
)
})
}
</div>
<div className="card__info">
<div className="card__data card__data--weight">
<p className="title">Weight:</p>
<p>{pokemon.weight}</p>
</div>
<div className="card__data card__data--height">
<p className="title">Height:</p>
<p>{pokemon.height}</p>
</div>
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} Temporary for dev puprose */}
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
)}
</div>
</div>
</div>
);
}
export default Card;
You can use the index of the array may be your data is having some kind of duplicate. It is recommended that you pass a key prop whenever you are returning a list.
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={i} pokemon={pokemon} />
})}
</div>
Equally, check this segment of card components.
{
pokemon.types.map((type,i) => {
return (
<div key={i} className="card__type" style={{backgroundColor:
typeColors[type.type.name]}}>
{type.type.name}
/div>
)
})
}
And
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} }
{pokemon.abilities.map((ability, i) => <p key={i}>{ability.ability.name}
</p>
)}
</div>
Previous answer will solve your problem. However, for your info, I would also like to add here.
For React a key attribute is like an identity of a node/element/tag which helps React to identify each item in the list and apply reconciliation correctlyon each item. Without a key React will render your component but may cause issue when you re-order your list.
React recommends to use id of the data instead of index number. However, if your list does not re-orders/ sorts or do not have id then you can use index.
You can read more here:
https://reactjs.org/docs/lists-and-keys.html
Change this:
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
to:
<div className="card__types">
{
pokemon.types.map((type, key) => {
return (
<div key={key} className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
and:
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
to:
{pokemon.abilities.map((ability,key) => <p key={key} >{ability.ability.name}</p>

Conditionally adding a row after 3 elements: ReactJS

I want to render several row containing three columns each. The columns have just a Card. The way I thought I could do this is to map through the elements and create a row when the index modulus is 0 and close that row when it's the third column of the row. I've tried with if-else statements and with ternary operators. But I keep getting syntax errors.
render(){
var { isLoaded, items } = this.state;
if(!isLoaded) {
return (<div> Fetching items </div>);
}
else {
var results = items.results;
return (
<div className="App">
<div className ="container">
{ result.map ((result, i) => {
return(
{i%3===0 ?
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>);
}
{i%3===1 ?
</div>
:null}
})}
</div>
</div>
);
}
}
With this piece of code I'm getting an error in this line
{i%3===0 ?
How can I solve this?
Because, you have a unclosed <div> tag which is invalid JSX, also { in return means an object not dynamic content.
Don't forget we write JSX, not html. Each tag needs to be closed properly, because it will get converted into React.createElement(component/html tag, props, children).
To solve the problem, first prepare the array and after 3 items, just push the elements in row arrays, like this:
renderRows() {
let results = items.results;
let finalArr = [], columns = [];
result.forEach ((result, i) => {
// prepare the array
columns.push(
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
);
// after three items add a new row
if((i+1) % 3 === 0) {
finalArr.push(<div className ="row mt-4">{columns}</div>);
columns = [];
}
});
return finalArr;
}
render(){
var { isLoaded, items } = this.state;
if(!isLoaded) {
return (<div> Fetching items </div>);
} else {
return (
<div className="App">
<div className ="container">
{this.renderRows()}
</div>
</div>
);
}
}
You are getting the error, because you are not rendering a valid element each time - it is missing a closing tag when "i%3===0" resolves to true.
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
</div> // <-- this one
Also, you could just render all the cards in that one container and set the style of the card accordingly to be the width of a third of the parent container.
<div className="container">
{result.map((result, i) => {
return (
<div key={i} className="col-md-4"> // add styles for width 30%
<Card result={result} />
</div>
);
})}
</div>
And one other idea is that instead of feeding data like [1,2,3,4,5], you could reduce the array to buckets of other arrays like [[1,2,3], [4,5,6]] and render those.
<div className="container">
{result.map((row, i) => (
<div key={i} className="row mt-4">
{row.map((col, i) => (
<div key={i} className="col-md-4">
<Card result={col} />
</div>
))}
</div>
))}
</div>
P.s. don't use the index for the element key. Use something unique, like the value of the card or an id.
You are simply missing some closing brackets.
Try this,
<div className ="row mt-4">
{ result.map ((result, i) => {
return(
<React.Fragment>
{(i%3===0) ?
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
}
</React.Fragment>
)
})}
</div>
As per your code,
{ result.map ((result, i) => {
return(
{i%3===0 ?
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>); //You have added `);` which is cause of error. this means you are returning this much part only.
Here's how you can fix it:
render() {
const { isLoaded, items } = this.state;
if (!isLoaded) {
return (<div> Fetching items </div>);
}
const results = items.results;
return (
<div className="App">
<div className="container">
{results.map((result, i) => (
<React.Fragment>
{(i + 1) % 4 === 0 ?
(<div className="row mt-4" key={`row-${i}`}>
<div key={i} className="col-md-4">
<Card result={result} />
</div>
</div>) :
(<div key={i} className="col-md-4">
<Card result={result} />
</div>)}
{i % 3 === 1 ? <div /> : null }
</React.Fragment>
))}
</div>
</div>
);
}
I strongly suggest you to use ESLint or linter to find and fix these errors then and there. Take a look at: https://medium.com/#RossWhitehouse/setting-up-eslint-in-react-c20015ef35f7. Eslint will help you with better indentation, matching brackets, best practices and much more. Once you have set eslint, you can sort these out yourself.
Edit:
Grouping items into four and putting them under one row:
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
isLoaded: true,
items: {
results: ["1", "2", "3", "4", "5", "6", "7", "8"]
}
};
}
render() {
const { isLoaded, items } = this.state;
if (!isLoaded) {
return (<div> Fetching items </div>);
}
const results = items.results;
// Group them into sets of 4.
const grouped = results.reduce((acc, post, ind) => {
var index = parseInt(ind / 4);
acc[index]= acc[index] || [];
acc[index].push(<div key={`colmn-${index}`} className="col-md-4">{results[ind]}</div>);
return acc;
}, []);
return (
<div className="App">
<div className="container">
{grouped.map((row, i) => {
return <div className="row mt-4" key={`row-${i}`}>{row}</div>})}
</div>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById("retrospect-app"));
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet"/>
<div id="retrospect-app"></div>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>

Categories

Resources