react-native-fast-image
react-native-fast-image copied to clipboard
Placeholder image.
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).
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.
I really think that it would be awesome to have a placeholder.
Yes, placeholder is definitely a must! Great plugin, btw.
@DylanVann any update on the placeholder? Or any workarounds to have a placeholder(defaultImage) ?
Great library and waiting for placeholder feature
@DylanVann : Are there any news? I saw this: https://github.com/DylanVann/react-native-fast-image/issues/109#issuecomment-351889257
@Angelk90! That's not a wise solution! It's better to handle with onLoadEnd
method.
@AlirezaAkbarix : You could be more specific. Can you give an example?
@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 – Would it be possible for you to provide a code snippet for your proposed method?
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.
@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? 🙏
Is there any plan in adding defaultimage as a placeholder?
This PR adds placeholder
prop https://github.com/DylanVann/react-native-fast-image/pull/409
What's wrong with just adding defaultSource
? https://facebook.github.io/react-native/docs/image.html#defaultsource
** 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
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 setfallback
so that on an error, it falls back to<Image />
which supportsdefaultSource
@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.
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!
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 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.
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.
I feel quite upset that this placeholder feature is still not implemented yet white SDWebImages lib supports it since the very early release. SAD
@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.
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}
/>
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.
Solved in both Android and iOS in https://github.com/DylanVann/react-native-fast-image/pull/550
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?
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>
@deepgosalia1 The steps are "replace the package's version with the git repo url"