2

I am trying to load images from URL on flatlist using Image Component. In this component there is a property (onError?: () => void ) this property is called on an image fetching error. When I run my app in low network some images failed to load, so what code should I write in (onError?: () => void ) so that the URL that failed to load images should load one more time in low network.

I am creating this App in React Native for iOS

I have done this :

App.js

import React, { useState } from 'react';
import Product from './product';
import {
  FlatList,
  SafeAreaView
} from 'react-native';

const products = [
  {productImage: "https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612"},
  {productImage: 'https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612'},
  {productImage: "https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612"},
  {productImage: 'https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612'},
]

const App = () => {
  return (
    <SafeAreaView>
      <FlatList 
      numColumns={2}
      data={products}
      keyExtractor={(item, index) => index.toString()}
      renderItem={({ item }) => (<Product product={item} />)}>
</FlatList>
    </SafeAreaView>
  );
};

export default App;

product.js

import React from 'react';
import { View, Image } from 'react-native';

class Product extends React.Component {

    constructor(props){
     super(props);
     this.state = {
       uri : this.props.product.productImage,
       errorCount : 0
     }
    }

    passInError(e) {
      const { productImage } = this.props.product
          if (this.state.errorCount < 3) {
            this.setState({uri: productImage, errorCount: ++this.state.errorCount})
            console.log(" Corrupt Image URL : " + productImage )
            console.log(" Corrupt Image Error Reason : ", JSON.stringify(e) )
            console.log (" Corrupt Image Reload Count : ", this.state.errorCount)
          }
        }

    render() {
        return (
            <View>
              <Image
                 style={{ width: 200, height: 200, borderWidth: 2, }}
                 source={{ uri:this.state.uri }}
                 onError = {e => this.passInError(e.nativeEvent) }
                 key = {this.state.errorCount}
              />
            </View>
        )
    }
}

export default Product;

What code should I write in (onError?: () => void ) function to reload failed images URL ?

Sarthak
  • 29
  • 1
  • 6

2 Answers2

1

Try setting image url in state and update when error on loading image.

product.js

import React from 'react';
import { View } from 'react-native';
import FastImage from 'react-native-fast-image';

class Product extends React.Component {
    constructor(props){
     super(props);
     this.state = {
       uri : this.props.product.productImage,
       errorCount : 0
     }
    }

    render() {
        const { productImage } = this.props.product
        return (
            <View>
              <FastImage
                 style={{ width: 200, height: 200, borderWidth: 2, }}
                 source={{ uri:this.state.uri }}
                 resizeMode={FastImage.resizeMode.contain}
                 onError={e =>
                   this.state.errorCount < 3 &&
                   this.setState(
                     {uri: '', errorCount: ++this.state.errorCount},
                       () => this.setState({uri: productImage}),
                   )
                 }
              />
            </View>
        )
    }
}

export default Product;
Thanhal P A
  • 4,097
  • 3
  • 18
  • 38
  • Hello Thanhal...I repleace my Product.js with yours..it showing me error : TypeError: undefined is not an object (evaluating '_this.props')... what should I do next ? – Sarthak Mar 07 '22 at 10:37
  • Sorry missed super(props). try now with updated code – Thanhal P A Mar 07 '22 at 10:49
  • Yes I added super(props)..Now it is showing error : ReferenceError: Can't find variable: uri.. – Sarthak Mar 07 '22 at 11:26
  • Sorry again, I passed uri like in hooks(forgot about this.state). Now please try again with updated code. – Thanhal P A Mar 07 '22 at 12:39
  • Hello @Thanhal....I forgot to add one more thing in my question that : I have to reload Images only for 3 time in OnError property....And it will be very helpful if we can reload only those images that failed to load.. – Sarthak Mar 09 '22 at 06:12
  • Updated code with error count state – Thanhal P A Mar 09 '22 at 06:36
  • Thanks @Thanhal for the updated code...I have one query that is there any possible way that we can only reload those images which were failed to load earlier ? – Sarthak Mar 09 '22 at 08:01
  • https://github.com/DylanVann/react-native-fast-image#onerror---void : onError called on an image fetching error. So only images which were failed to load earlier get reloaded. – Thanhal P A Mar 09 '22 at 08:13
  • Hello @Thanhal...I have added this line of code to print corrupt image url and error count : [ console.log(" product image : ", productImage ) console.log (" err count : ", this.state.errorCount) ].... but error count is increasing only for 0 and 1 times....I am getting this output on terminal :- LOG product image : {corrupt url} LOG err count : 0 LOG product image : {corrupt url} LOG err count : 1 ......I have to reload it for 4 times. I have attached image of added code and output in my question – Sarthak Mar 10 '22 at 06:37
  • Since we are assigning same uri, it will act as no update in state thats why FastImage reloads only one time, try with updated code when onError with initially setting url as empty string then change to productImage uri – Thanhal P A Mar 10 '22 at 08:36
  • 1
    Thanks @Thanhal..I replaced FastImage with React Image and implemented your logic in that and It worked fine for me..I am updating product.js in my question...you can check there.. thanks again – Sarthak Mar 11 '22 at 05:34
1

If I understand you correctly, you want to try to load the same image for a 2nd time when there is an error on the 1st try. I would try to re-render the component on Error (even better, wrap the image component with a wrapper component so that the whole Product component is not re-rendered):

const Product = () => {
  const [fetchCounter, setFetchCounter] = useState(0);

  return (
    <img 
      src={'imageUrl'}
      onError={() => {
        if (fetchCounter < 1) {
          setFetchCounter(fetchCounter++);
        }
      }} 
    />
  )
}

I do not know your use case, but you can load a fallback image instead. It could look something like this:

const Product = () => {
  const [imageUrl, setImageUrl] = useState('product-img-url');

  return (
    <img 
      src={imageUrl}
      onError={() => setImageUrl('fallback-img-url')} 
    />
  )
}
blend
  • 142
  • 5