react-native-fast-image icon indicating copy to clipboard operation
react-native-fast-image copied to clipboard

Placeholder image.

Open grundmanise opened this issue 7 years ago • 34 comments

Hi, thanks for this very useful lib! It would be great if we could set a placeholder image (to show it while the image is loading).

grundmanise avatar May 21 '17 11:05 grundmanise

Yeah I was thinking of including that but cut it to get the lib released. I'll take a look at how that could be done now.

DylanVann avatar May 22 '17 01:05 DylanVann

I really think that it would be awesome to have a placeholder.

zakster12 avatar Jul 21 '17 09:07 zakster12

Yes, placeholder is definitely a must! Great plugin, btw.

gitlovenotwar avatar Aug 26 '17 12:08 gitlovenotwar

@DylanVann any update on the placeholder? Or any workarounds to have a placeholder(defaultImage) ?

pavanmehta91 avatar Nov 10 '17 05:11 pavanmehta91

Great library and waiting for placeholder feature

wellyshen avatar Feb 08 '18 02:02 wellyshen

@DylanVann : Are there any news? I saw this: https://github.com/DylanVann/react-native-fast-image/issues/109#issuecomment-351889257

Angelk90 avatar Feb 18 '18 16:02 Angelk90

@Angelk90! That's not a wise solution! It's better to handle with onLoadEnd method.

AlirezaAkbarix avatar Apr 28 '18 10:04 AlirezaAkbarix

@AlirezaAkbarix : You could be more specific. Can you give an example?

Angelk90 avatar Apr 28 '18 11:04 Angelk90

@Angelk90! You set placeholder prop as default source, then use onLoadEnd method to replace that placeholder with new grabbed image (this method should be changed to return image).

AlirezaAkbarix avatar Apr 29 '18 03:04 AlirezaAkbarix

@AlirezaAkbarix – Would it be possible for you to provide a code snippet for your proposed method?

Meandmybadself avatar May 09 '18 19:05 Meandmybadself

Hi! I solved it by using a wrapper component. This is my wrapper component.

PlaceHolderFastImage

codingwaysarg avatar Jun 18 '18 15:06 codingwaysarg

Not sure if other people have this issue but I tend to get a blink when using the wrapper on pages where the image is visible on page load.

staffannase avatar Aug 28 '18 10:08 staffannase

@DylanVann Is there any update on this particular feature? I did see that you mentioned in https://github.com/DylanVann/react-native-fast-image/issues/109#issuecomment-384457112 that it would probably get added. Is it on the roadmap? 🙏

craigcoles avatar Jan 29 '19 13:01 craigcoles

Is there any plan in adding defaultimage as a placeholder?

zeekay18 avatar Feb 01 '19 12:02 zeekay18

This PR adds placeholder prop https://github.com/DylanVann/react-native-fast-image/pull/409

EgidioCaprino avatar Feb 19 '19 09:02 EgidioCaprino

What's wrong with just adding defaultSource? https://facebook.github.io/react-native/docs/image.html#defaultsource

timothystewart6 avatar Feb 27 '19 19:02 timothystewart6

** Edit ** Now that I've read the request more this won't address the placeholder feature but it is a workaround for a fallback so I'll leave the comment. Hope this helps.

I've managed to do it like this:

      <FastImage          
          source={{
            uri: `https://www.example.com/example.png`,
          }}
          fallback
          defaultSource={require(../images/fallback.png))}
        />

I don't think defaultSource works with <FastImage /> but it does with <Image /> so I set fallback so that on an error, it falls back to <Image /> which supports defaultSource

timothystewart6 avatar Feb 27 '19 20:02 timothystewart6

What's wrong with just adding defaultSource? https://facebook.github.io/react-native/docs/image.html#defaultsource

@timothystewart6 so is it just a matter of naming? I think a placeholder prop is more suitable for this case.

** Edit ** Now that I've read the request more this won't address the placeholder feature but it is a workaround for a fallback so I'll leave the comment. Hope this helps.

I've managed to do it like this:

      <FastImage          
          source={{
            uri: `https://www.example.com/example.png`,
          }}
          fallback
          defaultSource={require(../images/fallback.png))}
        />

I don't think defaultSource works with <FastImage /> but it does with <Image /> so I set fallback so that on an error, it falls back to <Image /> which supports defaultSource

@timothystewart6 that is great, but covers only the case when an error occurs and you still want to display a default image. It does not cover the case where the actual image is being loaded and you want a placeholder in the meantime.

EgidioCaprino avatar Feb 28 '19 10:02 EgidioCaprino

What's wrong with just adding defaultSource? https://facebook.github.io/react-native/docs/image.html#defaultsource

@timothystewart6 so is it just a matter of naming? I think a placeholder prop is more suitable for this case.

Not just naming, it handles both the default and fallback. Wouldn't just passing prop through to the underlying <Image /> component work? Maybe I am misunderstanding. Sorry!

timothystewart6 avatar Feb 28 '19 17:02 timothystewart6

Here is the code that works in my specific use case

            <View>
              { !this.state.isImgLoaded && (
                <FastImage
                  style={{
                    width: 400,
                    height: 450,
                    position: 'absolute',
                  }}  
                  source={{uri: photo.uri}}
                  resizeMode={FastImage.resizeMode.contain}
                />  
              ) } 
              <FastImage
                style={{
                  width: 400,
                  height: 450,
                }}  
                source={{uri: photo.images[this.state.count % photo.images.length]}}
                onLoadEnd={this.handleImgLoaded}
                resizeMode={FastImage.resizeMode.contain}
              />  
            </View>

elsewhere -

  handleImgLoaded = () =>
    this.setState({ isImgLoaded: true })

Great package btw! One of the better written packages out there.

sanealytics avatar Mar 07 '19 16:03 sanealytics

@sanealytics what is the first image that you render when !this.state.isImgLoaded? Is that a sort of placeholder? If so, why do have to remove it when the actual image is loaded? If you would not remove it that the placeholder would remain when some error occurs while displaying the actual image.

EgidioCaprino avatar Mar 07 '19 19:03 EgidioCaprino

That is a good idea @EgidioCaprino but it doesn't work for me. I load a super low res default of the first image as photo.uri, and then rotate through the array of high res photo.images. If I don't hide it on first image load, the default photo will flash before the next one does.

Your use case might differ.

sanealytics avatar Mar 14 '19 17:03 sanealytics

I feel quite upset that this placeholder feature is still not implemented yet white SDWebImages lib supports it since the very early release. SAD

zackhsuan avatar May 16 '19 06:05 zackhsuan

@codingwaysarg I've rewritten your wrapper to suit my needs and I think it's cleaner: https://gist.github.com/lucasfeijo/8dc8cdb52558744103cbc3bfe1c617f8

Throwing it out there for anyone that needs a placeholder with fast-image.

lucasfeijo avatar Jul 05 '19 16:07 lucasfeijo

import React from 'react'

import FastImage from 'react-native-fast-image'
import PLACE_HOLDER_DEFAULT from '../assets/images/placeholder_default.png';


class SmartImage extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            imageLoading: true
        }
    }

    imageLoadProgress = (e) => {
        this.setState({ imageLoading: false })
        this.props.onProgress && this.props.onProgress(e)
    }
    imageLoadError = () => {
        this.setState({ imageLoading: false })
        this.props.onError && this.props.onError()
    }

    imageLoad = (e) => {
        this.setState({ imageLoading: true })
        this.props.onLoad && this.props.onLoad(e)
    }

    render() {
        let { source } = this.props
        const { style, resizeMode } = this.props
        const { imageLoading } = this.state

        source = imageLoading ? source : (this.props.placeholder || PLACE_HOLDER_DEFAULT);

        return (
            <FastImage
                {...this.props}
                style={style}
                source={source}
                fallback={!this.state.imageLoading}
                onError={this.imageLoadError}
                onProgress={this.imageLoadProgress}
                onLoad={this.imageLoad}
            />
        )
    }
}


export default SmartImage

To use elsewhere

<SmartImage style={styles.somestyle}
                  source={{ uri: item.someuri }}  placeholder={{uri: globalplaceholderURL }}
/>

<SmartImage style={styles.somestyle}
                  source={{ uri: item.someuri }}  placeholder={REQUIRE_PLACEHOLDER}
/>

qalqi avatar Aug 13 '19 14:08 qalqi

I've prepared custom wrapper using hooks.

import React, { useState, useMemo, memo } from "react";
import PropTypes from "prop-types";
import { View, StyleSheet } from "react-native";
import CachedImage from "react-native-fast-image";

const FastImage = memo(
  ({
    renderPlaceholder,
    renderErrorImage,
    onError,
    onLoad,
    imageStyle,
    ...otherProps
  }) => {
    const [isLoading, setLoading] = useState(true);
    const [isErrored, setIsErrored] = useState(false);

    const CachedImageMemoized = useMemo(() => {
      return (
        <CachedImage
          {...otherProps}
          style={[imageStyle, styles.image]}
          onError={() => {
            setLoading(false);
            setIsErrored(true);
            onError && onError();
          }}
          onLoad={e => {
            setLoading(false);
            onLoad && onLoad(e);
          }}
        />
      );
    }, [onError, onLoad, imageStyle, otherProps]);

    return (
      <View style={imageStyle}>
        {CachedImageMemoized}
        {isLoading && renderPlaceholder()}
        {isErrored && renderErrorImage()}
      </View>
    );
  }
);

FastImage.priority = CachedImage.priority;
FastImage.resizeMode = CachedImage.resizeMode;

FastImage.propTypes = {
  renderPlaceholder: PropTypes.func,
  renderErrorImage: PropTypes.func,
  onError: PropTypes.func,
  onLoad: PropTypes.func,
  imageStyle: PropTypes.object.isRequired
  // Your imageStyle can look like:
  // imageStyle = {width: XYZ, height: XYZ}
};

const styles = StyleSheet.create({
  image: { position: "absolute", zIndex: -1 }
});

export default FastImage;

I've tried solutions above but I noticed some perforamnce issues. This works for me really well. And it will work for you also if you will memoize props in parent component.

Using this solution you are free to use any react component as Placeholder image and any react component as Error image too.

sebqq avatar Sep 05 '19 09:09 sebqq

Solved in both Android and iOS in https://github.com/DylanVann/react-native-fast-image/pull/550

danielgindi avatar Sep 18 '19 18:09 danielgindi

Solved in both Android and iOS in #550

@danielgindi I went through your forked repo and the fixing of the placeholder issue. Can you please explain the steps in general to replace @DylanVann's npm module in my project with yours? Do i just copy and replace his files with yours in the nodemodule's folder? or is there any other way?

deepgosalia1 avatar Jun 18 '20 15:06 deepgosalia1

Seems still no support for a placeholder, following is my workaround for placeholder

<View> { loading && <MImage containerStyle={imageStyle} uri={placeholderUri} /> } <FastImage style={loading?{width:0, height:0}:imageStyle} source={uri} onLoad={()=>{ setTimeout(()=>{ setLoading(false) },100) }} resizeMode={FastImage.resizeMode.contain} /> </View>

muhammad786 avatar Jul 13 '20 09:07 muhammad786

@deepgosalia1 The steps are "replace the package's version with the git repo url"

danielgindi avatar Jul 13 '20 17:07 danielgindi