Inline if-else with conditional operator not working React - reactjs

I've been struggeling with this basic stuff for a while now, but I cant seem to get it to work.
I'm getting data from our backend and if there're any deliveries objects it will be displayed with this:
<Expandable>
<ObjectDisplay
key={id}
parentDocumentId={id}
schema={schema[this.props.schema.collectionName]}
value={this.props.collection.documents[id]}
/>
</Expandable>
But if there is no deliveries I'd like to display a message like there's no deliveries. I can use .length and !deliveries (I get that), but it seems like my conditional isn't working:
render() {
console.log(this.props.collection.ids.length) //Getting how many deliveries there are with their id
return (
<div>//Struggling with this:
{!this.props.collection.ids && this.props.collection.ids.length < 1
? <p>No deliviers</p>
: <div className="box">
{this.props.collection.ids
.filter(
id =>
// note: this is only passed when in top level of document
this.props.collection.documents[id][
this.props.schema.foreignKey
] === this.props.parentDocumentId
)
.map(id => {
return (
<Expandable>
<ObjectDisplay
key={id}
parentDocumentId={id}
schema={schema[this.props.schema.collectionName]}
value={this.props.collection.documents[id]}
/>
</Expandable>
)
})}
</div>}
</div>
)
}
I bet my problem is super basic, but I just can't get it to work.. Help is much appreciated!!

Change your && to ||. You want to render "no delivers" if you have no ids (first test) OR if your ids.length is < 1

Your problem seems indeed to be with your condition.
!this.props.collection.ids && this.props.collection.ids.length < 1
!this.props.collection.ids is only true when the array is falsy. However, an empty array is not falsy - it's truthy.
this.props.collection.ids.length < 1 is true when the array is empty.
Since you are doing && you require the array to be falsy and empty at the same time, which can never happen.
So simply change the condition from && to || and it should work. In other words:
!this.props.collection.ids || this.props.collection.ids.length < 1
though I think this is prettier:
!this.props.collection.ids || !this.props.collection.ids.length

Your condition throws an error. See here
!this.props.collection.ids && this.props.collection.ids.length < 1
^
!false && undefined
Change your condition to
this.props.collection.ids && this.props.collection.ids.length > 1
and put your placeholder in the else block of your ternary.

Related

react classname 3 conditional rendering hide with display none

I have 3 variables that I must evaluate to hide a div if a condition is met between these 3 variables, something like this:
appState.fullResults
appState.someResults
appState.otherResults
So, when appState.fullResults and appState.someResults come empty, but appState.otherResults has something, I need to hide a div, this code snippet is an example:
<div classname='container'>
<div classname='full-some'>
boxes
</div>
<divclassname='others'>
boxes
</div>
</div>
I try something like this, but dont work
className={`${
(!appState.someResults?.length > 0 && otherResults?.length > 0)
? 'container-boxcard'
: 'd-none'
}`}
I always get the same result: if othersResults brings something and someResults brings nothing, the "d-none" is not passed to hide it
https://imgur.com/bZBUGo9
Still evaluates false and applies the d-none class
Hope I have explained well, thank you for your help.
Try this :
const { fullResults, someResults, otherResults } = appState;
const className = !fullResults?.length && !someResults?.length
&& otherResults?.length ? 'd-none' : 'container-boxcard';
<YourComponent className={className} {...props} />
!appState.someResults?.length > 0 is hard to understand, I'd suggest you should change it to !appState.someResults?.length or appState.someResults?.length === 0 (you can choose one of them).
I haven't seen you declared otherResults anywhere else, so I'd assume that otherResults?.length > 0 should be appState.otherResults?.length (or appState.otherResults?.length > 0).
className={`${(!appState.someResults?.length && appState.otherResults?.length)
? 'd-none'
: 'container-boxcard'
}`}
when appState.fullResults and appState.someResults come empty, but appState.otherResults has something
According to your demonstration, you can follow this with 3 conditions
className={`${(!appState.someResults?.length && !appState.fullResults?.length && appState.otherResults?.length)
? 'd-none'
: 'container-boxcard'
}`}
finally it was a problem with the function that created the objects fullResults, someResults & otherResults, it was passing all the answer to the object, creating another object inside, that's why always the object even if it had no data inside, evaluated length greater than 0 because it had something inside,
setAppQuotationState({
loading: false,
fullResults: fullResults?.length > 0 ? [fullResults] : [],
someResults: someResults?.length > 0 ? [someResults] : [],
otherResults: otherResults?.length > 0 ? [otherResults] : [],
})
}
correcting that bug, the solutions that I indicated, worked well.

Even though I check there exsist a data, the error message shows "Cannot read properties of undefined" in React

I am just getting started learning React one month ago. I am sorry if I asked a pretty easy question in advance.
Here is an issue,
what's the problem?
: I got data from back-end that is called "setWeekendEventData". When I console WeekendEventData, I can check I received the data that I want.
Here, I only want DayName. In this case, there are two DayNames. So, I tried to use the 'map' method because sometimes the DayName could be one or two or more than three.
First, I tried to like this
{weekendEventData.map((obj, index) => {
return <RedText>{obj[index].DayName}</RedText>;
})}
However, I got this error message "Cannot read properties of undefined (reading 'DayName')"
What I tried to do
{weekendEventData && weekendEventData.map((obj, index) => {
return <RedText>{obj[index].DayName}</RedText>;
})}
and
{[] && weekendEventData.map((obj, index) => {
return <RedText>{obj[index].DayName}</RedText>;
})}
I add the && condition to make it always true but there is the same error message. Usually, I solved this kind of error message by using && condition but it didn't work this time.
Using "Condition ? : " but it also didn't work
What I expected: It should be return DayName which is '개천절' and '한글날'
I would really appreciate your comments or solution!
edit 1:
const holiday = data => {
let array = [];
for (let i = 0; i <= 6; i++) {
if (data) {
if (array.includes(data[i])) i++;
else array.push(data[i]);
}
console.log("데이터 값", data[i]);
console.log("휴무일 배열", array);
}
and in the functional component
<RedText>{holiday(weekendData)}</RedText>
You use index wrongly here
obj[index].DayName
It should be corrected safely as below
obj.DayName || ""
Following will work with duplicates removed
<RedText>
{weekendEventData &&
weekendEventData
.reduce((prevValue, currValue) => {
prevValue.indexOf(currValue.DayName) < 0 &&
prevValue.push(currValue.DayName);
return prevValue;
}, [])
.join(", ")}
</RedText>

How to render jsx based on some condition using ternary operation in react?

i want to render the jsx based on a condition using ternary operation in react.
What i am trying to do?
i have the code like below that works perfect.
return (
{this.has_rendered() && this.items_loaded()
? <ChildComponent/>
: <ChildComponent
on_prev={null}/>}
)
Now i want to check for other condition if its !current_user then i want to pass another prop named "on_next" to ChildComponent.
{this.has_rendered() && this.items_loaded() && !current_user &&
<ChildComponent/>}
{!this.has_rendered() && !this.items_loaded() && !current_user &&
<ChildComponent on_prev={null}/>}
{this.has_rendered() && this.itemss_loaded() && current_user &&
<ChildComponent
on_next={somevalue}/>}
{!this.has_rendered() && !this.items_loaded() && current_user &&
<NavigationContent
on_prev={null}
on_next={somevalue}/>}
The above code works but as you see there is repetition of code. how can i fix this with ternary operator. could someone help me with this.
thanks.
Nested ternary is a bad idea.
You should use variables in this case
let component = null;
if (this.has_rendered() && this.items_loaded()) {
component = current_user? <ChildComponent/> : <ChildComponent on_prev={null}/>
} else {
component = ...
}
If on_prev and on_next attributes can have values all the time, consider this approch:
return (
{ this.has_rendered() &&
<ChildComponent
on_prev={this.items_loaded() ? somevalue : null }
on_next={current_user ? someanothervalue : null} />
}
)

Utilizing AND statement (two conditions) inside react ternary operator

below is a inline if with logical && operator that renders a component if this.state.isHidden is false.
<div>{!this.state.isHidden && <ShowThisComponent /> }</div>
The above line works as expected. My problem is that I cannot figure out how to add a second condition to be met (e.g var1 === var2) to the above line. So that if both return true, the component gets displayed. How can I do this? thanks
I've looked at the documentation (https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical-ampamp-operator) could not find an answer
This is how the operator works:
{<any boolean statement> && <Component-to-be-displayed />}.
-or-
{(<any boolean statement>) && <Component-to-be-displayed />} ... it's always a good idea to use parentheses when analysing boolean statements
In your case it would look something like this :
(!this.state.isHidden && var1 === var2) && <Component-to-be-displayed />
so think of the operator like this:
if condition is true && render component
You can also perform an if-statement:
{(<any boolean statement>) ?
<Component-to-be-displayed-if-true />
:
<Component-to-be-displayed-if-false />
}
you can think of this operator like this:
if condition is true ? render component A : else render component B
{ (!this.state.isHidden && var1 === var2) && <ShowThisComponent /> }
{ !this.state.isHidden && secondCondition && <ShowThisComponent /> }

best practise with optional parts on html rendering

I was wondering of a good way to conditionnally render a list of items. Basically I want to render a warning message, if there's a warning, I want to render message to contain a list of all the problems, here is my current approach :
text = (
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{(() => {
if (e.infos.error === "warning")
return <li>informations</li>
})()}
{(() => {
if (e.links.error === "warning")
return <li>links</li>
})()}
{(() => {
if (e.file.error === "warning")
return <li>file</li>
})()}
</ul>
</div>);
that's ugly, but I wanted to test something, so another approach I took was something like that :
function optionalWarning(props) {
if (props.error === "warning")
return <li>{props.message}</li>;
return null;
}
....
text = (
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
<optionalWarning error="e.infos.error" message="informations" />
<optionalWarning error="e.links.error" message="links" />
<optionalWarning error="e.file.error" message="file" />
</ul>
</div>);
This is prettier, but I don't like the fact that I have to make an external functions to do that, I suppose the best practise is the second one, but are there other ways to do that ?
Use logical operators - the right hand side of these statements will only be used if the left hand side is truthy.
Otherwise, if the left hand side is false, undefined or null, React won't render anything.
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{e.infos.error === "warning" && <li>informations</li>}
{e.links.error === "warning" && <li>links</li>}
{e.file.error === "warning" && <li>file</li>}
</ul>
</div>
You have to be careful to always ensure a false, undefined or null result when your check fails - e.g. if you're checking the length of a list with {list.length && <Something/>}, when the list is empty this will evaluate to 0 and React will render it as text, whereas a check like {list.length > 0 && <Something/>} will work as you expect.
Use ternary operator for conditional rendering, it will be easy to write conditions inside JSX.
Like this:
<div>Orange fields are not mandatory, are you sure you want to submit without :
<ul>
{e.infos.error === "warning" ? <li>informations</li> : null }
{e.links.error === "warning" ? <li>links</li> : null}
{e.file.error === "warning" ? <li>file</li> : null}
</ul>
</div>
I would go for:
<ul>
{ e.infos.error === "warning" && <li>informations</li> }
{ e.links.error === "warning" && <li>links</li> }
{ e.file.error === "warning" && <li>file</li> }
</ul>

Resources