Cannot convert undefined or null to object in React JS - reactjs

I have a problem about implementing conditional rending in return part of functional component.
I got this kind of error shown below.
Cannot convert undefined or null to object
While some links have more than one link, others have only one link.
How can I fix my issue?
Here is my code shown below.
{Object.keys(projectDialog?.links).length > 1 ? (
projectDialog?.links
.map((link, index) => (
{link.icon}
))
) : (
{projectDialog?.links.icon}
)
}

You need additional check for cases if projectDialog or projectDialog?.links are null or undefined, for better readability and prevent from nested ternary conditional rendering I would write in such way:
...
if (!projectDialog || !projectDialog?.links) return null;
//after above check you can be sure that below return will be with defined values
return (
{Object.keys(projectDialog?.links).length > 1 ? (
projectDialog?.links.map((link, index) => (
{link.icon}
))
) : (
{projectDialog?.links.icon}
)
}
)

Related

"Object is possibly undefined" in React and TypeScript

certificate?: any;
<S.Contents>{certificate[0]}</S.Contents>
<S.Contents>{certificate[1]}</S.Contents>
<S.Contents>{certificate[3]}</S.Contents>
If the type of props is set to any and used as an index of an array, it works well. But if you change that any type to Array, Generic type'Array' requires 1 type argument(s). I get an error like this.
When I print typeof to the console, the object comes out, so when I change it from Array to object, I get an error other. "Object is possibly 'undefined'."
setCertificate(res.data.qualification.certificate);
Since it is an original array, I tried to create elements by turning it into map, but it also didn't work with a map is not a function error. I don't know what to do with me. Help.
You Always have to check for possible null or undefined values.
This is how I would do it to make it 100% safe
return (<div> {
certificate && certificate.length > 0 ? (
certificate.map((item, index) => (
<S.Contents key = {index}> {item}</S.Contents>
))
) : null
} </div>)
You get this error because you used an optional property for certificate. You need to add a check for undefined, to make sure it is actually defined.
Assuming your react function looks something like this, this would be a fast way to solve your issue:
function ReactComponent(props: {
certificate?: any[]
}) {
const certificate = props.certificate || [];
return (
{certificate.map((certificateItem) => (
<S.Contents>{certificateItem}</S.Contents>
))}
);
}
This line const certificate = props.certifate || []; assigns the first value if it is not undefined to the variable certificate otherwise the second. An if statement would also work but would be more verbose in this case:
function ReactComponent(props: {
certificate?: any[]
}) {
let certificate = props.certificate;
if(typeof certificate === "undefined") {
certificate = [];
}
return (
<div>
{certificate.map((certificateItem) => (
<S.Contents>{certificateItem}</S.Contents>
))}
</div>
);
}

refactor react code to check state null condition

I have working react-native code as sample below, I plan to refactor for readable reason, basically I need to check if state.room has content then return Text with then content of field
return (
{ state.room ?
<Text>{state.room.name}</Text>
: null }
{ state.room ?
<Text>{state.room.address}</Text>
: null }
);
You can use { state.room && <Text>{state.room.name}</Text> } instead.
You can simply check that state.room is truthy before you are trying to touch it once before the return statement and then assume it is fine.
if (!state.room) {
return null;
}
return (
<React.Fragment>
<Text>{state.room}</Text>
<Text>{state.room.address}</Text>
</React.Fragment>
)
You can just simply check write as
return state.room && (
<>
<Text>{state.room.name}</Text>
<Text>{state.room.address}</Text>
</>
)
If fragment shorthand is not supported, you can write as React.Fragment instead of <>.
It will return only render the markup if state.room is not falsy.

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

Create a basic loop in React

I got React noob question.. The thing is that I have great number of fuctions that is almost indentical except that the method name and the properites is the differences between this two code blocks.
In my example, the first method is named xxx and the next yyy. The properties are named aaa and bbb.
To the question, how can I loop this in a smart way so I don't need a bunch of almost identical methods? I want to have only one method.
xxxx(blogItemNum: number) {
return (
this.state.dataLoadedLeadershipBlogDataItems ? (
this.state.leadershipBlogDataItems.length > blogItemNum ?
<aaaa item={this.state.leadershipBlogDataItems[blogItemNum]} index={blogItemNum} labels={this.props.labels} /> : ""
)
: ""
);
}
yyyy(blogItemNum: number) {
return (
this.state.dataLoadedLeadershipBlogDataItems ? (
this.state.leadershipBlogDataItems.length > blogItemNum ?
<bbbb item={this.state.leadershipBlogDataItems[blogItemNum]} index={blogItemNum} labels={this.props.labels} /> : ""
)
: ""
);
}
Ideally, don't do the index check in the method at all, pass item and index directly into the function:
xxxx(item, index: number) {
return (
<aaaa item={item} index={index} labels={this.props.labels} />
);
}
That is, just move the common code out of the method to another shared place.
Also, if you are looping correctly over this.state.leadershipBlogDataItems, you won't actually need this.state.leadershipBlogDataItems.length > blogItemNum checks.

Inline if-else with conditional operator not working React

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.

Resources