Proper way to handle null value in javascript function - javascript

I have following code
getState(dc) {
let state = data.channels[channelId]?.channelStatus.find(item => {
item.dc === dc
})
return state;
}
in some cases i am getting channelStatus as [null] and throwing error cannot read property of null
How can i handle this in javascript?

What this function should return depends on what the calling code expects. Using optional chaining will prevent the code from throwing an error, but will instead return undefined, which may not be what the calling code expects.
You need to handle this by either returning a default value in case your first expression doesn't return anything, or changing the calling code so that it can appropriately deal with a return value such as undefined.
You can return a default value in case your first expression evaluates to undefined by using the nullish coalescing operator:
getState(dc) {
const defaultValue = ''; // whatever your default value is
return data.channels[channelId]?.channelStatus?.find(item =>{item.dc === dc}) ?? defaultValue;
}

Related

Loop through an object if property does not always exist or is undefined

I want to build a table in Raect with a sorted list of watches of a certain ebay listing.I figured out that the problem is this line:
entriesObj[value][1][0].listingInfo[0].watchCount[0]
because sometimes listing don't have any watches at all and in this case value watchCount doesn't exist at all so I can't loop through it, although I tried to use conditional operator (and if else statements in many different ways) it still throws an error. First I created an object:
watcherCount = () => {
return (
this.state.itemList.reduce((watcherObject,item) => {
const watcherKey = item.itemId;
if (!watcherObject[watcherKey]) {
watcherObject[watcherKey] = [item];
} else {
watcherObject[watcherKey].push(item);
}
return watcherObject;
},{})
);
}
and now I am trying to move them to an array ([number of watches, title of listing, item id]) in order to sort them:
import React from 'react';
class Watches extends React.Component {
render () {
var entriesObj = Object.entries(this.props.watcherCount);
var sortable = [];
for (var value in entriesObj){
for (var value in entriesObj){
sortable.push([typeof entriesObj[value][1][0].listingInfo[0].watchCount[0] === "undefined" ? "-" : entriesObj[value][1][0].listingInfo[0].watchCount[0], entriesObj[value][1][0].title[0], entriesObj[value][0]]);
}
}
sortable.sort(function(a, b) {
return b[0] - a[0];
});
console.log(sortable);
//Output: Uncaught (in promise) TypeError: Cannot read property '0' of undefined
return <table></table>
}
}
export default Watches;
Do you know any other way to build this exact kind of array or how to solve the problem with missing property?
I Don't know if I fully understood the problem.
In cases with deep references, if I don't want or can't use any conditional checks I simply put the object path reference in a try catch (finally) block.
e.g. (untested though)
for (var value in entriesObj){
var val;
try {
// just make sure the only error that might be occuring
// here is an object reference error
// therefore the array push happens after the try catch block
val = entriesObj[value][1][0].listingInfo[0].watchCount[0], entriesObj[value][1][0].title[0], entriesObj[value][0]];
} catch(err) {
val = "-";
// log the error or maybe issue a warning since missing items
// is actually expected behaviour
} finally {
sortable.push(val);
}
}
Maybe it solves your problem.

React 16.4 ComponentDidMount not respecting strict equality checks

The issue
Hello I'm running into a bit of a proplem using ComponentDidMount.
I wish to perform a network request if the value is not undefined, it will be undefined when the component mounts, the value will be passed when a user is redirected by using the state that lives inside of location which I will passed to the component usinghistory.push(route, state);
Consider the code below, I only posted the code in question since the other lines are irrelevant to the issue.
As you can see below I am making a network request if the data I'm performing an equality check on is not undefined, this indeed works when the user redirects because the value exists since the user performed an action which calls history.push(route, state); passing the route and the desired data to be passed, however if the user visits the component without first being redirected by using history.push(route,state) it will be undefined by default, in this case I'm checking to see if the value is defined or not, which should perform the equality check and not execute anything at all, instead the console throws me an error pointing to my logic for the issue, does ComponentDidMount respect equality checks for undefined properties?
componentDidMount() {
this.loadData();
if (this.props.location.state.editData !== 'undefined') {
const { asOfDate } = this.props;
const { editData } = this.props.location.state;
const { batchName, fileName } = editData;
this.getFile(asOfDate, fileName, batchName );
}
}
this is the error I am getting
Cannot read property 'editData' of undefined
at SingleTransactionContainer.componentDidMount
You are trying to access a key in an undefined object.
So you should assure that you can access the value of your key.
The best way to do it is:
(((this.props || {}).location || {}).state || {}).editData
which will return undefined if you are not receiving your props.
To resume, the problem is in your if condition and also undefined not "undefined" because if you compare
undefined === "undefined" --> false
Add below condition
if (this.props.location && this.props.location.state && this.props.location.state.editData !== 'undefined') {
const { asOfDate } = this.props;
const { editData } = this.props.location.state;
const { batchName, fileName } = editData;
this.getFile(asOfDate, fileName, batchName );
}

How to show/hide divs when a if/else condition is met in ReactJS from a data coming from JSON?

How can a div be shown/hidden when a condition is met in React, when the data comes from a JSON array? I've got this code so far, but when I change the value of isPassed={resultPass.pass} to isPassed={resultPass.failed} it still shows the result as pass.
The closest example I've found is this, but it does not fetch value from a JSON ( var resultPass in my code), but just assigns true/false value to a const.
var resultPass = {
"pass": "passpass",
"fail": "failfail"
}
function Passed(props) {
return <div class="result-pass"><h3>passpass</h3></div>;
}
function Failed(props) {
<div class="result-fail"><h3>failfail</h3></div>;
}
function ResultDisplay(props) {
const isPassed = props.isPassed;
if (isPassed) {
return <Passed />;
}
return <Failed />;
}
// When resultPass.pass is changed resultPass.fail it still shows as pass
render(<ResultDisplay isPassed={resultPass.pass} />, document.getElementById('root'));
Here is my Codesandbox.
That is because if (isPassed) { always evaluate to true. You should check the if condition properly like this
if (isPassed === "passpass") {
return <Passed />;
}
return <Failed />;
You're not properly checking the prop of ResultDisplay.
const isPassed = props.isPassed;
if (isPassed) {
return <Passed />;
}
return <Failed />;
isPassed will be either the string "passpass" or "failfail", but since your if statement is making a basic equivalency check, it is type converting both of your strings to a true boolean value. So, your if statement always evaluates to true and you're always returning <Passed />.
The proper way to check the equivalency of a string is with the more strict identity operator (===) which will not convert type and ensure that you're checking for the exact same string.
const isPassed = props.isPassed;
if (isPassed === "passpass") {
return <Passed />;
}
return <Failed />;
You also need to ensure that your Failed() function returns something, otherwise it will not work properly.
function Passed(props) {
return <div class="result-pass"><h3>passpass</h3></div>;
}
function Failed(props) {
return <div class="result-fail"><h3>failfail</h3></div>;
}

Why is flow erroring when using a switch statement to loop over keys in an object?

This is obviously a contrived example but I don't understand why flow is erroring in this case. The error I'm receiving from flow is on the call of map. It says the mothod cannot be called on a possibly undefined value.
You can see the error in flows live editor here.
The two things I'm not clear on is (questions repeated in code example as inline comments)
i. Should I even have to check that foo[key] is an array?
ii. Why does the flow error go away if I change the first break statement into a return statement?
/* #flow */
type Foo = {
myArray?: Array<string>
};
function test(foo: Foo) {
Object.keys(foo).forEach(key => {
switch (key) {
case "myArray":
/**
QUESTION 1:
I shouldn't have to check that foo[key] is an array because I've told flow that when I do
have a key called myArray it's going to be an array. If I remove this if statement
I get an error saying that I could be calling
*/
if (!Array.isArray(foo[key])) {
/**
QUESTION 2:
If I change this break statement to a return statement instead, flow linting passes and
it doesn't complain about the .map call below. Why?
*/
break;
}
const result = foo[key].map(s => {
return s + "1";
});
console.log(result);
break;
default:
break;
}
});
}
test({ myArray: ["foo"]});
test({});
QUESTION 1: You don't need to check for array type. Just check value for null.
(Type of value and result are for examples. They can be removed)
const value: ?Array<string> = foo[key];
if (value == null)
break;
const result: Array<string> = value.map(s => {
return s + "1";
});
try flow example
QUESTION 2: If value check for null, no flow errors happens.
Probably flow handles differently break and return statements.
It is better to prefer break over return inside switch inside loop. If forEach refactored to for(...) loop then return behavior is changed.
P.S. Object.assign's type definition seems to be broken
https://github.com/facebook/flow/issues/1149
I think this is something to do with Flow not being able to be sure that foo is not being mutated from outside the function. By creating a local shallow copy of foo everything is fine.
/* #flow */
type Foo = {
myArray?: Array<string>
};
function test(foo: Foo) {
const localFoo = Object.assign({}, foo);
Object.keys(localFoo).forEach(key => {
switch (key) {
case "myArray":
const result = localFoo[key].map(s => {
return s + "1";
});
console.log(result);
break;
default:
break;
}
});
}
test({ myArray: ["foo"]});
test({});

Overwrite getter logic for an instance of Immutable.js

I am using immutable.js to manage configuration object, e.g.
config.js
export default Immutable.fromJS({
foo: 'FOO',
bar: {
// ...
}
});
I would like to overwrite the getter functions so that accessing an undefined property would throw an error.
How do I do it given that every setter method of the resulting object will create a new instance of Immutable (in effect overwriting whatever monkey-patching)?
Generally I do not want it to throw an error, just handle undefined without causing the code to break fatally. To throw specific error I might use try/catch, but this is highly inefficient.
To prevent breakage I do something like this.
My motivation here is mostly that my call .get of undefined poops itself really hard, and initializing properly all over the place helps, but doesn't catch all edge cases. I just want the data or undefined without any breakage. Specific type checking causes me to do more work later if I want it to make changes.
This looser version solves many more edge cases(most if not all extend type Iterable which has .get, and all data is eventually gotten) than a specific type check does(which usually only saves you when you try to update on the wrong type etc).
/* getValid: Checks for valid ImmutableJS type Iterable
returns valid Iterable, valid Iterable child data, or undefined
Iterable.isIterable(maybeIterable) && maybeIterable.get(['data', key], Map()), becomes
getValid(maybeIterable, ['data', key], Map())
But wait! There's more! As a result:
getValid(maybeIterable) returns the maybeIterable or undefined
and we can still say getValid(maybeIterable, null, Map()) returns the maybeIterable or Map() */
export const getValid = (maybeIterable, path, getInstead) =>
Iterable.isIterable(maybeIterable) && path
? ((typeof path === 'object' && maybeIterable.getIn(path, getInstead)) || maybeIterable.get(path, getInstead))
: Iterable.isIterable(maybeIterable) && maybeIterable || getInstead;
//Here is an untested version that a friend requested. It is slightly easier to grok.
export const getValid = (maybeIterable, path, getInstead) => {
if(valid(maybeIterable)) { // Check if it is valid
if(path) { // Check if it has a key
if(typeof path === 'object') { // Check if it is an 'array'
return maybeIterable.getIn(path, getInstead) // Get your stuff
} else {
maybeIterable.get(path, getInstead) // Get your stuff
}
} else {
return maybeIterable || getInstead; // No key? just return the valid Iterable
}
} else {
return undefined; // Not valid, return undefined, perhaps should return false here
}
}
Just give me what I am asking for or tell me no. Don't explode. I believe underscore does something similar also.

Categories