React Conditional Rendering, avoid 0 evaluated to false/undefined - javascript

I have checked the other Q/As. Mine is a bit different and I'm new to ReactJS.
Following code for setting const variable evaluates 0 as false/undefined
and value returned from myFunc is "" :
function formatAmount(x){
if(x === undefined || x === null) return "";
return(x.toLocaleString("en-US",{style: "currency", currency: "USD"}));
}
//When user.bill.amount == 0 this line evaluates it to false!!
const amount = user?.bill?.amount || user?.statement?.amount;
function myFunc(){
return(formatAmount(amount));
}
I tried expanding it with a function and IF conditions but the value returned by myFunc is "$NaN":
const amount = () => {
if(user?.bill?.amount || user?.bill?.amount === 0){
return user?.bill?.amount;
}
if(user?.statement?.amount || user?.statement?.amount === 0){
return user?.statement?.amount;
}
}
Expected:
When user.bill.amount == 0, myFunc should return "$0.00"
Actual:
myFunc returns empty string when user.bill.amount == 0

I think the problem here is 0 is falsy so when using || operator 0 will evaluate to false.
const amount = user?.bill?.amount || user?.statement?.amount;
If your environment supports the nullish operator that would work here.
const amount = user?.bill?.amount ?? user?.statement?.amount;

Related

What does `value >= value` do in JavaScript?

Below is one of conditional statements from the source code of d3.min.
What is this checking for?:
value >= value
Here is the entire source code:
export default function min(values, valueof) {
let min;
if (valueof === undefined) {
for (const value of values) {
if (value != null
&& (min > value || (min === undefined && value >= value))) {
min = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null
&& (min > value || (min === undefined && value >= value))) {
min = value;
}
}
}
return min;
}
It could be a peculiar form of checking against NaN (EDIT: and undefined):
const foo = 0/0; // NaN
let bar;
console.log(foo >= foo);
console.log(bar >= bar);
Although why would anyone write it like that, instead of using the isNaN method, I cannot tell. It's shorter than, say !isNaN(value) && value !== undefined, but I'm not sure the tradeoff in legibility is worth it.
Here's the >= comparison table created with editing this JSFiddle.
You can see value >= value is true except when value = undefined or value = NaN:

Only evaluate parts of a condition when the corresponding flag is set

For example, I have flag1, flag2, flag3,..., flagN as boolean values for flags.
I need to write an if statement like this: If flagK is false, then turn off the "K" part of the condition:
if (condition0 && (flag1 && condition1) && (flag2 && condition2) ... && (flagN && conditionN))
{
// do something
}
// For example, if flag 2 is false then the condition should only be:
if (condition0 && (flag1 && condition1) && ... && (flagN && conditionN))
{
//do something}
}
Particularly, given an example like this (for demo only not my real problem):
const divby2 = false; //if this is false, then ignore the **i%2 === 0** below
const divby3 = true;
const divby4 = true;
const divby5 = true;
//......const divbyN....
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,42,45,241,526]
array.forEach((i) => {
if(i >= 0 && (divby2 && i%2 === 0) && (divby3 && i%3 === 0)) {
console.log(i) // output here should be 3,6,9,12 instead of nothing
}
}
)
Example Result:
The term you are looking for is "short-circuit" similar to the way in real electronic circuit if some part is not working you just short circuit it and by pass flow to rest
if(i >= 0 && ( divby2 && i%2 === 0 || !divby2) && (divby3 && i%3 === 0))
In this case if you are wanting that filtered number should be divisible by 2 that time you set divby2 = true
And when you just want to ignore and don't care about the divisibility by 2 you set divby2 = false
In pseudo
(is-checking-for-divby-2? AND is-current-number-divby-2?) OR (NOT is-checking-for-divby-2?)
As soon as you are not checking for divby 2 you make this logic fragment true so it won't affect evaulation of the follolwing logic fragments
And..Why should you bother making this fragments TRUE?
Because you ANDing them
Similarly you can go for divby3, divby4 ...
I would have an object with your conditions, and then filter out the functions you don't want to run, and then just reduce the object to a single function which runs all of the enabled functions:
const conditions = {
divby2: i => i % 2 === 0,
divby3: i => i % 3 === 0,
};
const enabled = {
divby2: false, //if this is false, then need to ignore the **i%2 === 0** below
divby3: true
}
const enabledConditions = (i) => {
return Object.entries(conditions).filter(
([key, value]) => enabled[key]
).reduce((carry, [_, condition]) => {
return condition(i) && carry
}, i !== false);
}
//......const divbyN....
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,42,45,241,526]
array.forEach((i) => {
if(i >= 0 && enabledConditions(i)){
console.log(i) //output here should be 3,6,9,12 instead of nothing
}
}
)

Prevent value of 0 evaluating to false when using logical OR

I am wondering if there was a way around this issue. I am currently storing a value in a variable like so:
Session['Score'] = 0;
Later I have an assignment like so:
Score = Session['Score'] || 'not set';
The problem is, when Session['Score'] is set to 0 as above, JavaScript will interpret it as:
Score = false || 'not set';
which means Score will evaluate to 'not set' instead of 0!
How can I get around this issue?
Nowadays you can use the nullish coalescing operator (??) instead of the logical OR. It is similar to the logical OR, except that it only returns the right-hand side when the left-hand side is nullish (null or undefined) instead of falsy.
score = Session['Score'] ?? 'not set';
Old answer:
The cleanest way is probably to set the value and then check if it is falsy but not equal to 0
let score = Session['Score'];
if (!score && score !== 0) {
score = 'not set';
}
As mentioned by Patrick Roberts, you could also choose to use the conditional (ternary) operator in combination with the in operator:
Score = 'Score' in Session ? Session.Score : 'not set'
You can do this with destructuring assignment:
let { Score = 'not set' } = Session;
If it's not set:
const Session = { };
let { Score = 'not set' } = Session;
console.log( Score );
If it is set to any value other than undefined, including falsy ones:
const Session = { Score: 0 };
let { Score = 'not set' } = Session;
console.log( Score );
You could be more explicit about your intent by creating a few functions:
function getScore(s)
{
var result = s["Score"];
if (result == null) {
result = 0;
}
return result;
}
function addScore(s, v)
{
var result = s["Score"];
if (result == null) {
result = 0;
}
result += v;
s["Score"] = result;
return result;
}
var Session = {};
document.write("Score ");
document.write(getScore(Session));
document.write("<p/>");
addScore(Session, 10);
document.write("Score ");
document.write(getScore(Session));
Expected output:
Score 0
Score 10
Use a string instead:
Session['Score'] = "0";
Score = Session['Score'] || 'not set';

make a insert function for bracket.js

I'm a making function that replace null by another word/value.
the var in question :
var saveData = {"teams":[[null,null],[null,null]]}
I find out that the variable is a 2D array and to acces a null I shoud do savedata.teams[0][0] so i made a script that modify the variable.
function add(team, data)
{
var str = team.innerHTML;
var str = str.replace(/<td>/g, "");
var text = str.split("</td>");
var i = 0;
while(data.teams[i][0] != null || data.teams[i][1] != null)
{
i++;
}
if( i == data.teams.length - 1){}
if(data.teams[i][0] == null)
{
data.teams[i][0] = text[1];
}
else if(data.teams[i][0] != null)
{
data.teams[i][1] == text[1];
}
$(function() {
var container = $('.creator')
container.bracket({
init: data,
save: saveFn,
userData: ""})
})
}
the result is wierd. it output :
first use :
{"teams":[["team 1",null],[null,null]]}
seconde use :
{"teams":[["team 1",null],["team 2",null]]}
I don't know why, but I suspect the error may come from the while or the if
data.teams[i][0] != null || data.teams[i][1] != null if any of the two value is not null... it move to next element....
its supposed to be:
while(i < data.teams.length)
{
i++;
}
if(data.teams[i][0] == null)
{
data.teams[i][0] = text[1];
}
if(data.teams[i][0] != null)
{
data.teams[i][1] == text[1];
}
Check more into logical operators here.
Logical AND (&&)
Returns expr1 if it can be converted to false; otherwise, returns
expr2. Thus, when used with Boolean values, && returns true if both
operands are true; otherwise, returns false.
Logical OR (||)
Returns expr1 if it can be converted to true; otherwise, returns
expr2. Thus, when used with Boolean values, || returns true if either
operand is true.

optional arguments and default value

I am new to javascript does the following 2 functions does the same thing and would you pick one over another?
var multiply = function(arg1, arg2) {
arg1 && (arg1 = 0);
arg2 && (arg2 = 0);
return arg1*arg2;
}
var multiply = function(arg1, arg2) {
arg1 = arg1 || 0;
arg2 = arg2 || 0;
return arg1*arg2;
}
the reason i am asking is i saw something like this for the first time
function(path, limit) {
var ref = firebaseRef(path);
limit && (ref = ref.limit(limit)); //if i understood correctly this line does an assignment based on condition without an if statement
return $firebase(ref);
}
function(path, limit) {
var ref = firebaseRef(path);
limit && (ref = ref.limit(limit)); // Important
return $firebase(ref);
}
The Important line, can be written like this
if (limit) {
ref = ref.limit(limit);
}
But if you wanted to write it like the first way, you would have done,
ref = limit && ref.limit(limit)
This has one problem, when limit is Falsy && immediately returns the evaluated Falsy value of limit, so ref is Falsy now. You wouldn't have wanted this, I believe.
At the end of the day, as a programmer, readability and maintainability of the code of the code what we write matters. So, I would recommend using an explicit if check, which I mentioned at the beginning of the answer.
Note: Also, as noted by others, the first multiply should have been like this
var multiply = function(arg1, arg2) {
arg1 || (arg1 = 0);
arg2 || (arg2 = 0);
return arg1 * arg2;
}
Even better, I would have written it like this
var multiply = function(arg1, arg2) {
return (arg1 || 0) * (arg2 || 0);
}
Both are variable assignments which evaluate differently on the logical operation.
For example expr1 && expr2 will return expr1 if expr1 returns false otherwise the variable assignment will evaluate to the second expression (i.e. expr2).
Using the logical-or operation will return expr1 if it evaluates to true, otherwise it will return expr2.
Consider the following:
// Logical AND
var a1 = true && true; // t && t returns true
var a2 = true && false; // t && f returns false
var a3 = false && true; // f && t returns false
var a4 = false && (3 == 4); // f && f returns false
var a5 = "Cat" && "Dog"; // t && t returns Dog
var a6 = false && "Cat"; // f && t returns false
var a7 = "Cat" && false; // t && f returns false
// Logical OR
var o1 = true || true; // t || t returns true
var o2 = false || true; // f || t returns true
var o3 = true || false; // t || f returns true
var o4 = false || (3 == 4); // f || f returns false
var o5 = "Cat" || "Dog"; // t || t returns Cat
var o6 = false || "Cat"; // f || t returns Cat
var o7 = "Cat" || false; // t || f returns Cat
For more information, see: Mozilla Developer Network on Logical Operator Expressions
I think the first one will actually do the opposite of what you want. Let's test this with a few cases:
arg1 && (arg1 = 0);
If arg1 is 0, or any other falsy value, so the execution goes as follows:
0 (meaning false) AND an assignment. The expression will immediately return false without executing the arg1 = 0 statement, because false || (t/f) always returns false.
If arg1 is 1, or any other truthy value, so we have:
1 (meaning true) AND an assignment. The assignment will run this time, because it has to see what the second condition returns. Therefore, arg1 will be set to 0.
The correct snippet is the second.

Categories