Reputation: 358
I'm learning React and I'm trying to render 10 pieces of data from a specific API. This is a function I wrote for iterating through the fetched data and taking the title and the image:
for (let i = 0; i < 10; i++) {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs.src,
});
}
I don't know why but one of the images gives me that error:
index.js:1 TypeError: Cannot read property 'attribs' of undefined
Which stops the whole rendering. I wanted to try to put a temporary placeholder image so the rest of the images can be loaded without any errors.
I thought about adding conditions into the image line inside the loop but it didn't work for me. What's the right way to do that?
If I wasn't clear enough please comment what wasn't clear and I'll try to describe it better.
Upvotes: 0
Views: 1615
Reputation: 542
You can solve the null pointer exceptions in 2 ways.
?
or &&
Point 1 will solve your problem, but however if you start using it everywhere throughout your code it may not look tidy. I'd recommend to go by creating a utility function as below.
export const getSafe = (fn, defaultValue=null) => {
try {
return fn()
} catch (e) {
return defaultValue
}
}
You can then use it anywhere like..
var result = getSafe(() => object1.data.key)
You can use it for accessing any type of values to any depth. You can also pass a default value as 2nd argument if required. by default it is set as null
var resultArray = getSafe(() => array1.data.values, [])
Just remember, the 1st value should be passed as a function.
So in your case...
for (let i = 0; i < 10; i++) {
data.push({
title: getSafe(() => someMethod(allData)[i].children[0].data, "Default Title"),
image: getSafe(() => someMethod(allData)[i].attribs.src, "placehoder_img"),
});
}
Upvotes: 1
Reputation: 737
for (let i = 0; i < 10; i++) {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs?.src ?? defaultSrc,
});
}
docs: Optional_chaining and Nullish_coalescing_operator
Upvotes: 2
Reputation: 530
If someMethod
is synchronous (based on your code sample it should be) then you can wrap your code in try...catch
block like so:
for (let i = 0; i < 10; i++) {
try {
data.push({
title: someMethod(allData)[i].children[0].data,
image: someMethod(allData)[i].attribs.src,
});
} catch (err) {
data.push({
title: 'placeholder',
image: 'placeholder',
});
continue;
}
}
Here's more cleaner version of the above:
for (let i = 0; i < 10; i++) {
let title = '';
let image = '';
try {
title = someMethod(allData)[i].children[0].data;
image = someMethod(allData)[i].attribs.src;
} catch (err) {
image = 'failed to load or something';
}
data.push({title, image});
}
Upvotes: 2
Reputation: 869
Implement the map function. The for loop will give an error at your component In react if you need to render elements don't implement the for loop
datas.map(......)
Upvotes: 0