Hi when I have a condition output in frontend is there a possibility to make a else if () statement as well?
current code looks like:
{this.props.contentComponentData.typeOf === 1
&&
<ContentComponentChecklistInstances
checklistItems={this.props.contentComponentData.checklists}
/>
}
Thanks in advance
You can use the conditional operator to make if/else expressions:
{someCondition === true ? (
<TrueComponent/>
) : (
<FalseComponent/>
)}
If you want an if/elseif/else, you can combine multiple conditionals together:
{someCondition === true ? (
<IfComponent/>
) : someOtherCondition === true ? (
<ElseIfComponent/>
) : (
<ElseComponent/>
)}
These things can be difficult to read, so you should consider pulling this code up above your return statement, using normal if's and elses:
let component;
if (someCondition === true) {
component = <IfComponent/>
} else if (someOtherCondition === true) {
component = <ElseIfComponent/>
} else {
component = <ElseComponent/>
}
return (
<div>{component}</div>
);
{this.props.contentComponentData.typeOf === 1
&&
<ContentComponentChecklistInstances
checklistItems={this.props.contentComponentData.checklists}
/>
|| condition && ifConditionMetExpression
}
But this is a bit hard to read, I suggest you use ternaries instead:
{this.props.contentComponentData.typeOf === 1
? <ContentComponentChecklistInstances
checklistItems={this.props.contentComponentData.checklists}
/>
: condition
? ifConditionMetExpression
: null
}
(first condition)
? // if first condition true this part run
: (second condition)
? // if second condition true this part run
: // else part
Related
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>;
}
I want to render some part of Html only if one of the variable is true. I have seen examples where I can return the whole element but I only want a if condition on one part of the html. I only want to show with 10 lines if one of the variables is true but html with 500 lines is common. Can I do that in return function?
const getCustomers= (props) => {
useEffect(() =>{ do something...});
return (
<>
if(test === true){
<div> 10 lines</div>
else
{
do not show this div
}
}
<div> 500 lines</div> // Common
</>
)
};
Conditional rendering is only supported using ternary operator and logical and operator:
{
something ? '10 lines' : '500 lines'
}
{
something && '10 lines' || '500 lines'
}
if-else statements don't work inside JSX. This is because JSX is just syntactic sugar for function calls and object construction.
For further details, you may read this, and the docs
Try to avoid logic inside of your return statements.
You can assign your conditional output to a JSX value, and always render it.
const Customers = () => {
const optionalDiv = test === true && <div>10 lines</div>;
return (
<>
{optionalDiv}
<div>500 lines</div>
</>
);
};
you can use conditional (ternary) operator
return (
<>
{ test === true ? (<div> 10 lines</div>) : null }
<div> 500 lines</div>
</>
)
I think just doing it like this should do it -
return (
<>
{test? <div> 10 lines</div> : null}
<div> 500 lines which are common</div>
</>
);
I wonder how can use two state based booleans inside of the conditional rendering . For example i want to render a certain <div> element if one of the conditions are truthy and otherwise don't render it
Example :
{
this.state.visible && this.state.checked &&
<div>
...
</div>
}
In order to display my error message i use this example , but init i have the .length of the object so it is easy to use like :
{
this.state.ErrorMessage.length > 0 &&
<p>Error 404</p>
}
Can somebody give me heads up ? I am a little bit confused .
You can follow your way by parenthesis, to check both are true:
{
(this.state.visible && this.state.checked) && <div>...</div>
}
if you want one of is true:
{
(this.state.visible || this.state.checked) && <div>...</div>
}
Use it as a separate function which returns the components based on condition.
Example :
renderConditionalComponent() {
const { visible, checked } = this.state;
if (visible || checked) {
return <Component1 />;
}
// There could be other condition checks with different components.
// ...
return null;
}
render() {
// ...
return (
<div>
{this.renderConditionalComponent()}
{/* other components, etc */}
<OtherComponent />
</div>
);
}
I have a code like this
class EventDetails extends React.Component {
constructor( props ) {
super (props);
this.state={
startdate: props.startdate || "",
enddate: props.enddate || "",
venue: props.venue || ""
}
}
componentDidMount() {
fetch(`https://www.eventbriteapi.com/v3/venues/${this.state.venue}/?token=EventBrite'sTOKEN`)
.then(response => response.json())
.then(eventvenue => this.setState({ venue: eventvenue }))
}
render() {
const { startdate, enddate, venue } = this.state;
const getDateWhenTheEventStart = new Date(Date.parse(startdate));
const theDateWhenTheEventStart = getDateWhenTheEventStart.toDateString();
const theHourWhenTheEventStart = getDateWhenTheEventStart.getHours();
const theMinuteWhenTheEventStart = getDateWhenTheEventStart.getMinutes();
const getDateWhenTheEventEnd = new Date(Date.parse(enddate));
const theDateWhenTheEventEnd = getDateWhenTheEventEnd.toDateString();
const theHourWhenTheEventEnd = getDateWhenTheEventEnd.getHours();
const theMinuteWhenTheEventEnd = getDateWhenTheEventEnd.getMinutes();
function checkTime(time) {
if (time < 10) {
time = '0' + time
}
return time;
}
return(
<React.Fragment>
<Container text>
<Header as="h1">Date and Time</Header>
<p><strong>Starts:</strong> {theDateWhenTheEventStart} | {checkTime(theHourWhenTheEventStart)}:{checkTime(theMinuteWhenTheEventStart)}</p>
<p><strong>Ends:</strong> {theDateWhenTheEventEnd} | {checkTime(theHourWhenTheEventEnd)}:{checkTime(theMinuteWhenTheEventEnd)}</p>
<Header as="h1">Location</Header>
<List>
<List.Item>{venue.name}</List.Item>
{venue.address.address_1 != undefined && <List.Item>{venue.address.address_1}</List.Item>}
{venue.address.localized_area_display != undefined && <List.Item>{venue.address.localized_area_display}</List.Item>}
</List>
</Container>
</React.Fragment>
)
}
}
export default EventDetails;
The problem of the code is here
{venue.address.address_1 != undefined && <List.Item>{venue.address.address_1}</List.Item>} // gives me the error of 'Cannot read property 'address_1' of undefined'
I suspect that this problem occured because the component render first and the program breaks because the state is not updated yet.
Do you have any ideas how to solve this problem? Thank you
Make sure that the venue.address is not null before using venue.address.address_1
{venue.address && venue.address.address_1 !== undefined && <List.Item>{venue.address.address_1}</List.Item>}
You would have to do full error checking elsewhere - for example when you set the state.
But if you would like to do a one liner and do a full Error Check, following would be possible
<List>
<List.item>Date and Time</List.item>
{venue ? venue.address ? venue.address.address_1 ? <List.Item>{venue.address.address_1}</List.Item> : <List.Item>Loading..</List.Item> : <List.Item>Loading..</List.Item> : <List.Item>Loading..</List.Item>
</List>
However, as you can see, it's a very ugly way of doing it so do validity checking elsewhere if you want to use ternary
This is the safest full check if your object is defined or not with all properies during rendering (I think the cleanest too). It will render element if your object is fully valid.
{!!venue && !!venue.address && !!venue.address.address_1
&& <List.Item>{venue.address.address_1}</List.Item>
}
the best way of doing this is to use Object.prototype.hasOwnProperty() to check whether your object contains a particular key or not :
{venue.hasOwnProperty(address) &&
venue.address.hasOwnProperty(address_1) &&
<List.Item>{venue.address.address_1}</List.Item>}
Check something like below
{venue && venue.address && venue.address_1 ? .
{venue.address.address_1} : ''}
Here you can see, first we are checking if venue object is available then we check for the inner one and then nested object. This is the best practice instead of directly displaying the value. Hope this helps :)
It's always a good idea to check than an object and all nested objects you want to access have loaded. Please find an example of how I would check. When using the && operator, Javascript will check for the first false statement and then stop. In other words, if venue is "" (an empty string is considered false), null, or undefined, Javascript will stop checking at venue, before an error similar to the one you posted above is thrown.
If venue exists, it will then check venue.address, and so on, until finally, it will return the last statement "{venue.address.address_1}". If you try the code below, you'll see what I mean.
One last thing - please make sure the venue props are actually being passed to your component, or the two List.Item components will not render (though you will not get an error).
<List>
{venue && venue.name && <List.Item>{venue.name}</List.Item>}
{venue && venue.address && venue.address.address1 && <List.Item>{venue.address.address_1}</List.Item>}
{venue && venue.address && venue.address.localized_area_display && <List.Item>{venue.address.localized_area_display}</List.Item>}
</List>
Instead of long checks like a && a.b && a.b.c, use lodash get.
https://lodash.com/docs/4.17.10#get
<div style={{'backgroundColor': status === 'approved' ? 'blue' : 'black'}}>
</div>
black is the default color but what if I want to add the 3rd condition?
status can be 'approved', 'rejected', 'pending' or more.
You could do the following:
<div style={{'backgroundColor': status === 'approved' ? 'blue' : status === 'pending' ? 'black' : 'red'}}>
</div>
This means if status === 'approved' set the background color as blue, if status === 'pending' set it as black, else set it as red.
I would suggest using functions if your conditions get complicated, to not degrade your code readability.
getBackgroundColor(status) {
if (status === 'approved') {
return 'blue';
}
if (status === 'pending') {
return 'red';
}
return 'black';
}
render() {
// ...
return (
<div style={{ 'backgroundColor': this.getBackgroundColor(status) }}></div>
);
}
To chain ternary operations you need to add another ternary operator to be returned when the conditions are not met, for example:
a === true ? a : b
In place of b you would add a new ternary operator, like so:
a === true ? a : b === true ? b : c
Bonus:
When you're just checking for null/undefined/false you can use the pipe operator, for example this:
var x = a !== null ? a : b;
Can be simplified to:
var x = a || b;
And pipe operators can be chained infinitely like ternary operators.
There is another way how to do it with the a bit more readable & cleaner code style. We can replace the ternary operator with the object literal and use this instead of nesting ternary operators, like so
function getBackgroundColor(status){
const backgroundColorByStatus = {
approved: 'blue',
pending: 'black',
default: 'red',
}
return backgroundColorByStatus[status] || backgroundColorByStatus['default']
}
// somewhere below
<div style={{'backgroundColor': getBackgroundColor(status)}}>fancy div</div>
With this approach you can have multiple colors and code will be still clean & readable :)
Hope it will help.
Multiple condition in ternary operator in JSX and JS
style={{'backgroundColor': status === 'approved' ? 'blue' : status === 'cancel' ? 'red' : 'green'}}
Using multiple ternary operators is not a good idea, better to use a function and put if-else conditions inside that and call that function from render. It helps you to make the render part clean and short.
Like this:
<div style={{'backgroundColor': this._style(status)}}></div>
_style(status){
if(status == 'approved')
return 'blue';
else if(status == 'pending')
return 'black';
else return 'red';
}
I'd handle it separately as other types of status may appear in the future.
const getBackgroundColor(status) {
if (status === 'approved') {
return 'blue'
}
else if (status === 'pending') {
return 'black'
} else {
return 'red'
}
}
<div style={{'backgroundColor': getBackgroundColor(status) }}>
</div>
Code gets easier to understand and reason about.
I would not use ternary because it gets hard to read. Why not store the status and associated colors in an object then just reference that?
const colors = {approved:"blue", rejected:"red"};
<div style={{'backgroundColor':status in colors ? colors[status] : "black"}}>
</div>
Oops, I didn't realize how old this thread was.
Inside render you can create an empty array variable. As shown below, you can apply nested styling. Also, you won't need a nested ternary operator.
let styleValue = [];
if(status === 'approved') {
styleValue.push({backgroundColor:'blue'})
} else {
styleValue.push({backgroundColor:'black'})
}
<div style={styleValue}>
</div>