How to alphabetically list an already mapped array in javascript? - javascript

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>

Related

how to correctly refactor props/condition for easier reading React/Js

I would like to explain my problem of the day.
I have an element, and inside I have 2 conditions on props
when i reuse the component i call the props socialSupervisor or socialOperator.
it works perfectly.
on the other hand I find it long to read, so I am looking for a way of refactoring to have 0 props or 1 only.
I am open to any proposal thank you very much.
<p>
{socialSupervisor &&
(!isLoading &&
lastMessage?.type === "text" &&
lastMessage?.author?.type === "supervisor" &&
lastMessage?.author?._id === authUser._id ? (
<span>
Moi:
</span>
) : lastMessage?.author?.type === "operator" ? (
<span>
conseiller: {lastMessage?.author?.name}:
</span>
) : lastMessage?.author?.type === "supervisor" ? (
<span>
superviseur: {lastMessage?.author?.name}:
</span>
) : (
""
))}
{socialOperator &&
(!isLoading &&
lastMessage?.type === "text" &&
lastMessage?.author?.type === "operator" ? (
<span>
Moi:
</span>
) : lastMessage?.author?.type === "supervisor" ? (
<span>
superviseur: {lastMessage?.author?.name}:
</span>
) : (
""
))}
</p>
An improvement may be:
function getLabel(type) {
switch (type) {
case "operator":
return "conseiller";
case "supervisor":
return "superviseur";
case "me":
return 'Moi';
}
}
function renderSocialSupervisor() {
const isMe = lastMessage?.author?._id === authUser._id;
const label = getLabel(isMe ? 'me' : lastMessage?.author?.type);
return isLoading || lastMessage?.type !== "text" ? null : (
<span>{label}: {lastMessage?.author?.name}</span>
);
}
function renderSocialOperator() {
const isMe = lastMessage?.author?._id === authUser._id;
const label = getLabel(
lastMessage?.author?.type === "operator"
? "me"
: lastMessage?.author?.type
);
return isLoading || lastMessage?.type !== "text" ? null : (
<span>
{label}: {lastMessage?.author?.name}
</span>
);
}
return (
<p>
{socialSupervisor && renderSocialSupervisor()}
{socialOperator && renderSocialOperator()}
</p>
);
Better would be to write separate components, and to pass the right props to them. The less logic you put inside a single component return statement the better.
De-structure nested props/variables:
lastMessage to {author, type}
Or even refactor names of author and instead of _id and type to author_id and author_type, so you can de-structure easily:
{{author_id, author_type}, type}
I'll start by asking you what the types of socialSupervisor and socialOperator props? I can guess they're booleans (true or false), so if one of them is true, does it mean the other prop will be false?
If the answer is yes, you can use the ternary operator to render the component with one prop (you can decide which one to leave).
{ socialSupervisor ?
<span>Social supervisor render</span> :
<span>Social operator render</span> }
Secondly, I found that you re-use your spans, they share the same classes and only vary on their content.
If you ask me, I would create a function that returns the name of the author. Then, I would create a function that returns a span with the content I need.
const getAuthorLabel = (type, name) => {
switch (type) {
'me': return 'Moi: ';
'supervisor': return `superviseur: ${name}`;
'operator': return `conseiller: ${name}`;
default: return '';
}
}
const getAuthLabel = ({ author, type }) => {
const isMe = author?._id === authUser?._id;
const labelType = isMe && type === 'text' ? 'me' : author?.type;
const label = getAuthorLabel(labelType, author?.name);
return <span className="text-xs font-semibold mr-1">{label}</span>;
}
And last but not least, do you need these props? I mean, the last message would still be the last message, with all of its props, including the message type, author type, author name, author id, etc.
So maybe you could render the label directly in the paragraph element, without the need to check for their values. Of course, this is irrelevant if you need these props for something else, or they mean something else by themselves.
A whole refactor for the component, as I can imagine it would be something similar to this:
const YourComponent = ({ lastMessage }) => {
// your other logic goes here
return <p>{renderAuthLabel(lastMessage)}</p>;
}

Array.map render identical titles once

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>
)
})
}``

How to render jsx in react with condition true and array mapping?

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}
/>
)
);
})}
</>

React single line component

Hello I have a component which doesnt return anything. Im following a tutorial and the person is using newer syntax which confuses me a bit. The component looks like this:
const Alert = ({alerts}) => alerts !== null && alerts.length > 0 && alerts.map(alert => (<div key={alert.id} className={`alert-${alert.type}`}>{alert.msg}</div>));
I simply want to know how to write this without it being single line. So i can see what's going on. Much appreciated in advance. For as far as i am aware you always need to return something.
const Alert = ({ alerts }) => {
if (alerts !== null && alerts.length > 0) {
return alerts.map(alert => (
<div key={alert.id} className={`alert-${alert.type}`}>
{alert.msg}
</div>
));
}
return null
};
Things at play here are:
Arrow Functions
Array.Map
JSX
Template Literals
Basically its a component that takes in an alerts property (Array) as a prop (<Alert alerts={[...]} />). It checks whether the passed array is present and is not empty and then maps over it. For every item in the array, we are rendering a div containing the alert message.
Hope this helps!
Very roughly (i.e., untested):
const Alert = ({alerts}) => {
if ((alerts === null) || (alerts.length === 0)) {
return null
}
return alerts.map(alert => (
<div
key={alert.id}
className={`alert-${alert.type}`}
>
{alert.msg}
</div>
))
}
const Alert = ({alerts}) => {
if (!alerts || !alerts.length) return null
return (
<>
{alerts.map(alert => (
<div key={alert.id} className={`alert-${alert.type}`}>{alert.msg}</div>
)}
</>
)
}
I think what you are struggling with is generally the one-liner syntax, which doesn't need a return if there are no braces present.
What I mean is that this line
return alerts.map(alert => {
return (<div key={alert.id} className={`alert-${alert.type}`}>{alert.msg} </div>)
})
Would be the same as this line
return alerts.map(alert => (<div key={alert.id} className={`alert-${alert.type}`}>{alert.msg} </div>))

How to conditionally set an onClick attribute to component without having to repeat lines of nested code?

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>);
}

Categories