I have passwords array, I want to display those passwords - each password has a resource which should be displayed once as a title
So:
take resource as a title:
resource1: - password1 - password2 - password0,
resource2: - password4 - passwords5,
resource3: - password6 - password7 - password8 - password9
this.state.passwords && this.state.passwords.map((item, index) => {
return (
<>
{item[index] !== item[index + 1] && ( //here I am trying to do this logic
<Nav.Item><div className="sidebar-heading-secrets">{item.resource}</div></Nav.Item>
)}
<span>We render data here</span>
</>
)
})
}``
You are missing key in map. Use React.Fragment and supply a key
this.state.passwords && this.state.passwords.map((item, index) => {
return (
<React.Fragment key={index}>
{item[index] !== item[index + 1] && ( //here I am trying to do this logic
<Nav.Item><div className="sidebar-heading-secrets">{item.resource}</div></Nav.Item>
)}
<span>We render data here</span>
</React.Fragment>
)
})
}``
Related
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
}
}
)
)}
Having some issues on this, my code is supposed to hit an API, return a list of counties in a state, and display them. It does display just fine, however I want them to be in alphabetical order. Because this is a react component, I cannot understand where I would do a sort function, here is the part of the function that is mapped :
{error ? (
<h1>{error.message}</h1>
) : (
counties.map(function (county, index) {
if (
county.location.split(", ")[1] === stateName &&
county.location.split(" ")[0] !== "Unassigned" &&
county.location.split(" ")[0] !== "Out"
) {
return (
<div className="card" key={index}>
<h3>{county.location.split(",")[0]}</h3>
<p>confirmed: {county.confirmed}</p>
<p>dead: {county.dead}</p>
</div>
);
} else {
return null;
}
})
)}
</div>```
Sort right before mapping. Using this you might have duplicate code. What you can do instead is 1) map the fix the way you are handling the response, 2) sort using your own sorting function, since county seems to be JSON, and 3) Finally, map your stuff and return the JSX (the only thing that is rendered is the final return)
{error ? (
<h1>{error.message}</h1>
) : (
counties.sort(/* Sort function goes here */).map(function (county, index) {
if (
county.location.split(", ")[1] === stateName &&
county.location.split(" ")[0] !== "Unassigned" &&
county.location.split(" ")[0] !== "Out"
) {
return (
<div className="card" key={index}>
<h3>{county.location.split(",")[0]}</h3>
<p>confirmed: {county.confirmed}</p>
<p>dead: {county.dead}</p>
</div>
);
} else {
return null;
}
})
)}
</div>
Maybe this will help you.
Universal sorting function:
const sortDataByProperty = (data, property) => {
const sorted = [...data].sort((a, b) => {
return a[property].toLowerCase().localeCompare(b[property].toLowerCase());
});
return sorted;
};
Your Reactjs code:
{error ? (
<h1>{error.message}</h1>
) : (
// first parameter is data object
// second is object property by which you want to sort the data
const sortedData = sortDataByProperty(counties, 'name');
sortedData.map(function (county, index) {
if (
county.location.split(", ")[1] === stateName &&
county.location.split(" ")[0] !== "Unassigned" &&
county.location.split(" ")[0] !== "Out"
) {
return (
<div className="card" key={index}>
<h3>{county.location.split(",")[0]}</h3>
<p>confirmed: {county.confirmed}</p>
<p>dead: {county.dead}</p>
</div>
);
} else {
return null;
}
})
)}
</div>
I want to render a JSX with some condition being true and map through an array.
below is the code,
{this.props.variables &&
this.props.variable.map((variable, index) => {
let element;
if (variable.anchor) {
element = document.querySelector(variable.anchor);
}
this.box_ref.current && element && (// error here
<Childcomponent
element1={this.box_ref.current}
anchor={variable.anchor}
/>)
}
}
)
}
There is an error saying that the expression is not an assignment or a call. how can I fix it? thanks.
You need to provide a return value for #Array.map callback.
Also, you should provide unique keys to React elements within an array:
<>
{this.props.variables &&
this.props.variable.map((variable, index) => {
let element;
if (variable.anchor) {
element = document.querySelector(variable.anchor);
}
// v Add return statement
return (
this.box_ref.current &&
element && (
<Childcomponent
key={index}
element1={this.box_ref.current}
anchor={variable.anchor}
/>
)
);
})}
</>
I'm working inside a functional React component and I'm trying to render a 'Card' component with a conditional onClick based on the member's typename. A card should be clickable if its typename is 'Bundle' or 'LegacyArticle'. Any other typename should not have an onClick property.
I'm having trouble finding an efficient way to apply an onClick to a card without having a conditional with a bunch of lines of repeated code, (the code that would essentially be nested children of the 'Card' component).
So far, I've been able to render it conditionally from a function. This allows my return statement to have better readability but there is still a big chunk of code that gets repeated, and I want to find a way to reduce that.
return (
<div css={cards}>
{members && members.map((member, index) => (
renderCard(member, index)
))}
</div>
);
const renderCard = (member, index) => {
const isClickable = member.__typename === 'Bundle' || member.__typename === 'LegacyArticle';
if (isClickable) {
return <Card key={index} css={card} onClick={() => onCardClick(member)}>
{(member.__typename !== 'LessonSpark' &&
schemas[member.__typename].image(member)) &&
(<CardImage src={schemas[member.__typename].image(member)} />)}
<CardBlock css={cardType}>
{member.label || schemas[member.__typename].typename}
</CardBlock>
<CardBlock css={cardTitleStyle}>
{_truncate(schemas[member.__typename].title(member), 60)}
</CardBlock>
</Card>
} else {
return <Card key={index} css={card}>
{(member.__typename !== 'LessonSpark' &&
schemas[member.__typename].image(member)) &&
(<CardImage src={schemas[member.__typename].image(member)} />)}
<CardBlock css={cardType}>
{member.label || schemas[member.__typename].typename}
</CardBlock>
<CardBlock css={cardTitleStyle}>
{_truncate(schemas[member.__typename].title(member), 60)}
</CardBlock>
</Card>
}
};
As you can see, <Card> has children nested, and it's a lot of lines of code being repeated when essentially, the only difference is one has an onClick and one doesn't.
Any ideas on how I could possibly reduce this code and find a clean way to apply an onClick conditionally?
You can basically use DRY principle by only changing the unique / custom parts. So in this case the only difference i could see between the if and else statements was the onClick, so you can instead put the conditional there, if you want an onClick, in this case use a ternary or you could use &&.
const renderCard = (member, index) => {
const typename = member.__typename;
const isClickable = typename === 'Bundle' || typename === 'LegacyArticle';
const schema = schemas[typename];
const image = schema.image(member);
const cardContents = (typename !== 'LessonSpark' &&
image) &&
(<CardImage src={image} />);
return (<Card key={index} css={card} onClick={ isClickable ? () => onCardClick(member) : undefined}>
{cardContents}
<CardBlock css={cardType}>
{member.label || schema.typename}
</CardBlock>
<CardBlock css={cardTitleStyle}>
{_truncate(schema.title(member), 60)}
</CardBlock>
</Card>);
}
In addition to that, you can save the values from function calls and from properties of objects so that a) the code is easier to read/follow, and b) the code is a bit more optimized, since it is not doing unnecessary extra function calls.
One way to accomplish this is by adding the condition inside your Card onClick prop:
const isClickable = member.__typename === 'Bundle' || member.__typename === 'LegacyArticle';
return <Card key={index} css={card} onClick={isClickable ? () => onCardClick(member): null}>
{(member.__typename !== 'LessonSpark' &&
schemas[member.__typename].image(member)) &&
(<CardImage src={schemas[member.__typename].image(member)} />)}
<CardBlock css={cardType}>
{member.label || schemas[member.__typename].typename}
</CardBlock>
<CardBlock css={cardTitleStyle}>
{_truncate(schemas[member.__typename].title(member), 60)}
</CardBlock>
</Card>
Put onClick into an object and use prop spread.
const renderCard = (member, index) => {
const typename = member.__typename;
const maybeOnClick = typename === 'Bundle' || typename === 'LegacyArticle' ?
{ onClick: () => onCardClick(member) } : {};
const schema = schemas[typename];
const image = schema.image(member);
const cardContents = (typename !== 'LessonSpark' &&
image) &&
(<CardImage src={image} />);
return (<Card key={index} css={card} {...maybeOnClick}>
{cardContents}
<CardBlock css={cardType}>
{member.label || schema.typename}
</CardBlock>
<CardBlock css={cardTitleStyle}>
{_truncate(schema.title(member), 60)}
</CardBlock>
</Card>);
}
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.