'onLoadEnd is not fired in react-native Image

hi am trying to load an remote image. onLoadStart is hitting but not the onLoadEnd `

<View style={{ paddingTop: 60, paddingBottom: 10 }}>
              {this.state.loading ? (
                <DotIndicator size={25} color={"white"} />
              ) : (
                <Image
                  resizeMode={this.resizeMode}
                  style={[styles.imageStyle, this.tintStyle]}
                  onLoadStart={e => {
                    this.setState({ loading: true });
                  }}
                  onLoadEnd={e => this.setState({ loading: false })}
                  // defaultSource={NoProfile}
                  //  loadingIndicatorSource={require("@images/profile_placeholder.png")}
                  source={this.userImageUri}
                  onError={error => {
                    this.tintStyle = { tintColor: "lightgray" };
                    this.resizeMode = "contain";
                    this.userImageUri = NoProfile;
                  }}
                />
              )}
            </View>

`

EDIT 1

onLoadStart is hit. onLoad is also never being called

does any one have a clue. am new to react. Any help is appreciated. thanks is advance

SOLUTION

Since Vignesh and hong mentioned the image is never there so its on loadEnd will never be called. So instead of loading only image or loader I loaded the loader on top of image. Posting this here as it may be useful for someone at sometime. Once again thanks to Vignesh and hong

<View
              style={{
                padding: 10,
                width: WIDTH - 50,
                height: WIDTH - 25,
                alignSelf: "center"
              }}
            >
              {this.state.loading ? (
                <MaterialIndicator
                  size={50}
                  color={"red"}
                  style={{
                    marginTop: WIDTH / 2,
                    alignSelf: "center"
                  }}
                />
              ) : null}
              <Image
                resizeMode={this.resizeMode}
                style={[styles.imageStyle, this.tintStyle]}
                onLoadStart={e => {
                  this.setState({ loading: true });
                }}
                onLoad={e => {
                  this.setState({ loading: false });
                }}
                onLoadEnd={e => this.setState({ loading: false })}
                // defaultSource={NoProfile}
                //  loadingIndicatorSource={require("@images/profile_placeholder.png")}
                source={this.userImageUri}
                onError={error => {
                  this.tintStyle = { tintColor: "lightgray" };
                  this.resizeMode = "contain";
                  this.userImageUri = NoProfile;
                }}
              />
            </View>


Solution 1:[1]

Let's say that the value of this.state.loading was false before the first render.

When the first render happens, this.state.loading ? returns the Image component, onLoadStart is triggered and this.state.loading is set to true.

When the second render happens, this.state.loading is found to be true and this.state.loading ? returns the DotIndicator component. All the hard work done by the Image component during the previous the render is lost. In fact, Image component was never present in that context.

Hence, onLoadingEnd will never be triggered, because Image component never appeared in the second render.

And the DotIndicator will forever go round and round and round... Waiting for it's lost love..

Solution 2:[2]

If loading is true from the beginning, nothing will be called in the image.

If loading value is false at first, the image does not see loadStart running, only load function and loadEnd function will be called.

This is because the loadStart function runs when the start value is false and it is already rendered. And if the start value is true, nothing is done because it does not draw an image.

This is a very simple example that you can experiment with:

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

export default class App extends Component {
state={
 loading: false,
}
  render() {
    return (
      <View>
      {this.state.loading ? (
                       <Image
          style={{width: 100, height: 100}}
          source={{uri: 'https://facebook.github.io/react-native/img/tiny_logo.png'}}
        />
              ) : (
        <Image
          style={{width: 50, height: 51}}
          onLoadStart={e => this.setState({ loading: true })}
          onLoad={e => alert("onLoad")}
          onLoadEnd={e => alert("onLoadEnd")}
          source={require('@expo/snack-static/react-native-logo.png')}
        />)}
      </View>
    );
  }
}

Solution 3:[3]

I ended up copying the same image but set its style to width: 1, height: 1. this will always be displayed but is not visible. What this allows is to continue to set the state despite the many rerenders. I then in a if statement have the actual image or a text component that will display image not found. By default NoImageFound is set to true. Here is my code

    <Image
      source={{ uri: image }}
      style={{ width: 1, height: 1 }}
      onLoadStart={() => setNoImageFound(true)}
      onLoad={() => setNoImageFound(false)}
    />
    {noImageFound ? (
      <View style={{ justifyContent: "center", alignItems: "center" }}>
        <Text style={{ textAlign: "center" }}>No image found</Text>
      </View>
    ) : (
      <View style={styles.icon}>
        <Image source={{ uri: image }} style={styles.image} />
      </View>
    )}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Vignesh V Pai
Solution 2 hong developer
Solution 3 Freddie Banfield