Commando
Commando

Reputation: 358

how to set default value in case of error

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

Answers (4)

vineeth pappu
vineeth pappu

Reputation: 542

You can solve the null pointer exceptions in 2 ways.

  1. Manually check for truthy values using ? or &&
  2. Create a simple utility function

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

maltoze
maltoze

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

farhodius
farhodius

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

Vince
Vince

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

Related Questions