I am wanting to add after every 3rd .map item I am wondering if anyone knows of the correct way to do so, As if statements don't work and I am unsure how to achieve this result.
<Grid container spacing={3}>
{items.map(item => (
<MediaCard title={item.title} link={item.url} pic={item.image} category={item.category} tweet={item.TweetIDs}/>
))}
<GoogleAds />
</Grid>
I tried to put the if statement in the MediaCard function however realized that was wrong due to I need it to run as the items.map runs.
\
There are two different ways to achieve that. To get the third element, use the modulo % operator. It returns the rest obtained by dividing the number.
First you can use the filter function before the map function:
{items.filter((item, index) => index % 3 === 2)
.map(item => (
<MediaCard />)}
Or return false in map, which will lead to no rendering.
items.map((item, index) => (
index % 3 === 2 && <MediaCard />)}
Hope this helps. Happy coding.
The second parameter of map is the index of the item. So you could do:
<Grid container spacing={3}>
{
items.map((item, index) => (
<>
<MediaCard title={item.title} link={item.url} pic={item.image} category={item.category} tweet={item.TweetIDs}/>
{
((index + 1) % 3 === 0) && <GoogleAds />
}
</>
))
}
</Grid>
<Grid container spacing={3}>
{items.map((item, index) => {
if ((index + 1) % 3 === 0) {
return (
<MediaCard title={item.title} link={item.url} pic={item.image} category={item.category} tweet={item.TweetIDs} />
)
}
else {
return null;
}
})}
<GoogleAds />
</Grid>
Related
I have a list of elements and I would like to print 3 of them in cards in every row.
the problem with the following code : it prints just the first two elements and the loop stops.
here's my code im using reactjs and mui :
const testList = [//my list]
const ListInvoices = (props) => {
const invoicesList = () => {
for(let i = 1; i <= testList?.length; 3*i){
let invList = testList?.slice(i-1, 2*i)
return(
<Grid container alignItems="center" justifyContent="center">
<div style={{ display: "flex", flexDirection: "row" }}>
{invList ?.map((elt, index) => {
return(
<Grid item>
<Card sx={{m: 2}} key={{index}}>
{/* content of card */}
</Card>
</Grid>
)
})
}
</div>
</Grid>
)
}
}
return(
<Box sx={{ backgroundColor: "#f6f6f6" }} pt={4} pb={4}>
<Container maxWidth="lg">
{invoicesList()}
</Container>
</Box>
)
}
EDIT :
as the answers suggested, i changed this
for(let i = 1; i <= testList?.length; i*3)
//..
let invList= testList?.slice(i-1, 2*i)
to this
for(let i = 1; i <= testList?.length; i+3)
//..
let invList = testList?.slice(i-1, 3*i)
but the problem is always there
thank you in advance
Here is the relevant info for your problem
Loop inside React JSX
But could the problem be when you multiply i by 3,
for(let i = 1; i <= testList?.length; 3*i <-- here
Because when i = 1, i * 3 = 3, but when i = 3, i * 3 = 9, so it would skip the second row.
Edit
Seeing that your problem persists, and after reading again your code, I see a small detail that I didn't notice at first. Is your for loop working correctly? I have tried with RunJS and it's been creating infinite loops over and over again.
When you are doing i*3 you are not really updating the value of i, but making a simple declaration that has no further effects. Let me know if that makes sense, but this would be the code after the correction:
for(let i = 1; i <= testList.length; i = i + 3) {
Original answer
I'm not sure if I got your problem right. However, I do see why this line
invList ?.map((elt, index) => {
returns only 2 cards. I assume it's here where it had to return 3? If so, maybe I have an answer for you.
Mind that when using slice, the end index will not be included.
When applying the following code (extracted from yours):
let invList = testList?.slice(i-1, 2*i)
If index is 1 and the we have an array as the following one:
[0, 1, 2, 3, 4, 5]
invList will slice from 0 (index - 1) to 1, since 2 (2 * 1) will be the end index that is not included.
Therefore, the third number should be printed with the following small change:
let invList = testList?.slice(i-1, 3*i)
or
let invList = testList?.slice(i-1, 2*i + 1)
Having said so, is there any specific reason as of why you are using a for loop? I believe it could be replaced with map, using the second parameter passed at each iteration (the index parameter).
Well a friend of mine gave me a simple solution to achieve what I want, and also #Andy suggested to use the props of mui Grid. so here's the solution's code
const testList = [//my list]
const ListInvoices = (props) => {
return(
<Box sx={{ backgroundColor: "#f6f6f6" }} pt={4} pb={4}>
<Container maxWidth="lg">
<Grid container spacing={2} alignItems="center" justifyContent="center">
{testList?.map((elt, index) => {
return (
<Grid item xs={4}>
<Card sx={{m: 2}} key={{index}}>
{/*content*/}
</Card>
</Grid>
);
})
}
</Container>
</Box>
)
}
so by giving each item of the grid xs=4 (12/4 = 3) that prints in each row 3 cards and returns to new line for the next 3 items and so on ..
I would like to stop the loop inside bedsAssign.map if row.id is not equal to u.tenant_id but putting break; doesn't work.
{tenants.map((row) =>
bedsAssign.map(
(u) =>
row.id !== u.tenant_id && (
<MenuItem key={row.id} value={row.id}>
{row.fullName}
</MenuItem>
break; --> not working
)
)
)}
You can add filter before map to remove all bedsAssign items which are not matched with current row.id
{
tenants.map((row) =>
bedsAssign
.filter((u) => row.id !== u.tenant_id)
.map((u) => (
<MenuItem key={row.id} value={row.id}>
{row.fullName}
</MenuItem>
))
)
}
If you want to break the loop, you can try to use some or find with a proper return for map
{
tenants.map((row) => {
const isAssigned = bedsAssign.some((u) => row.id !== u.tenant_id)
return isAssigned ? (<MenuItem key={row.id} value={row.id}>
{row.fullName}
</MenuItem>) : null
})
}
You can not break any array methods like forEach, filter, map etc. If you encounter a scenario where you want your loop to break then you should use traditional for loop.
use a filter instead of map for bedsAssign:
{tenants.map((row) =>
bedsAssign.filter(
(u) =>
row.id !== u.tenant_id && (
<MenuItem key={row.id} value={row.id}>
{row.fullName}
</MenuItem>
)
)
)}
the filter is going to only fill in the items that are meeting the condition you want.
EDIT: I noticed that you want to break once condition is met, this would work in this case:
{tenants.map((row) =>
for(let i of bedsAssign){
if(row.id !== i.tenant_id && (
<MenuItem key={row.id} value={row.id}>
{row.fullName}
</MenuItem>
)){
break
}
}
)
)}
I've got the following code, and I need to add some new functionality to it. Basically, the map function is iterating through an array, and if there is only one item in the array, then I don't want to add a new class, but if this is the first item in an array of 2 items, I want to add a class name.
{section?.values?.link.map((link, index) => {
return (
<LinkComponent
key={index}
className={clsx({
"jc-left":
link?.values?.linkType !==
"primary-button",
})}
</LinkComponent>
...
I know it looks like the one that's already there, in that I put in the class name in quotes followed by a semicolon and then the rule, I just don't know how to write what seems like a complex rule to me. Any help is appreciated.
If I correctly understand your question is that you want to add className if you array.length > 1 and then add class to the first item of the array.
{section?.values?.link.map((link, index, self) => {
return (
<LinkComponent
key={index}
className={clsx({
"jc-left": link?.values?.linkType !== "primary-button",
"YOUR_CLASS": self.length > 1 && index === 0,
})}
</LinkComponent>
But what if you have more than two items then I assume that you will add class to all items except the last one
{section?.values?.link.map((link, index, self) => {
return (
<LinkComponent
key={index}
className={clsx({
"jc-left": link?.values?.linkType !== "primary-button",
"YOUR_CLASS": self.length > 1 && (index + 1 !== self.length),
})}
</LinkComponent>
If you want to render conditionally with clsx you can do this based on the two conditions:
{section?.values?.link.map((link, index) => {
// Checks if array has more than 2 or 2 items and if the index is 0 which means that is the first item.
const hasConditionalClass = section?.values?.link.length >= 2 && index === 0;
return (
<LinkComponent
key={index}
className={clsx({
"jc-left": link?.values?.linkType !== "primary-button",
"condtional-class": hasConditionalClass
})}
</LinkComponent>
...
I have been having trouble with this problem for a bit now. I use forEach to loop through an array, and I want the correct page to render with the corresponding index when I click on the component. Right now my issue is that I loop through my array, but I am not able to return the correct index, only the first one in the array. I want the startPage prop on the Pages component to render to correct index from my newNum variable.
const itemId = this.props.navigation.getParam('pk');
let newArray = this.props.moment.filter(item => {
return item.trip == itemId
});
console.log('getting moment fromt trip')
let num = Object.keys(this.props.trip[0].moments)
let newNum = num.forEach((number, index) => {
console.log(number)
return number
})
return (
// <View style={{flex:1, backgroundColor: '#F0F5F7'}} {...this.panResponder.panHandlers}>
<View style={{flex:1, backgroundColor: '#F0F5F7'}}>
<HeaderMomentComponent navigation={this.props.navigation} />
<Pages indicatorColor="salmon" startPage={newNum}>
{newArray.map((item, index) => {
console.log('this is the index')
console.log(index)
return(
<MomentContent
name={item.name}
place={item.place}
description={item.description}
tags={item.tags}
key={index}
/>
)
})}
</Pages>
</View>
);
According to MDN documentation (Mozilla Developer Network), return value of forEach is undefined.
Use Array#map to return a newNum value.
let newNum = num.map((number, index) => {
// Some logic to get a new number...
return number
})
very simple question, when I loop through array when rendering react compnent with .map function, say:
render() {
let board = this.props.board;
return (
<div>
{
board.map((piece,index) => {
return (
<Piece data={piece}/>
);
})
}
</div>
);
}
I'm trying to add a break line every 5 pieces so (index % 5 == 0) add <br /> before the <Piece />
when I try to concatinate with + or to do something like this:
board.map((piece,index) => {
return (
(index % 5 == 0) ? <br /> : ''
<Piece data={piece}/>
);
})
I'm getting an output of matrix of [Object object]'s
Return an array of [ <br />, <Piece> ] if the condition holds and return just the Piece component otherwise. See the fiddle.
The relevant piece of code is this:
return <div>{items.map(function (i, index) {
if (index % 5 === 0) {
return [ <br key={index + "break"} />, <Item key={index} num={i} /> ];
}
return <Item key={index} num={i} />;
})}</div>;
Also, put key on the components you return from map or other ways that return array-like instances. This way, React doesn't need to take out all the generated components and replace them on each render, but can just find them under the key and update their attributes. Check out Reconciliation in React docs to learn more.