Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
5 Things to know about Images in React Native
The more I work with React Native images, the more I find it tricky. I wrote about Image Caching without Expo, and with Expo. In React Native Sketch Elements and React Native Fiber, I’m using react-native-expo-image-cache. You can see it in action below.
Progressive image loading and caching in React Native Sketch Elements.
react-native-expo-image-cache is new, fits well in my projects but might not be flexible enough yet to fit your requirements. If it doesn’t, please let me know and please find below a list of fives things you ought to know about Images in React Native.
Don’t use prefetch()
React Native provides out of the box Image.prefetch which can be useful to pre-load images but in some cases but it is somewhat inadequate.
You really need the image to be present locally in order to avoid any flickering effect when loading it. It also allows to have more control over the cache of images. In the example below, you see the difference from using the Image.prefetch Image cache versus serving the image locally.
With prefetch on the left and with cache on the right
You might also need to display your image in a different component than <Image>. For instance in the example below we use <SVGImage> which only works for local paths and or data URIs.
Use ExpoKit
So you need to store images locally. If you use expo already, there is a File system library out of the box. If your project is detached, the react-native-fetch-blob library seems to has lost its main contributor. Last time I used it, it had some issues. It might be worthwhile to add ExpoKit as a dependency of your project even if you are "detached" from the get go. ExpoKit ships many other great components, including BlurView which can be natively animated in case you also want to implement progressive image loading.
Dealing with concurrency on Android
Many components might display the same image at the same time. And doing a Filesystem.exists(localURI) operation on Android will return true even if the file download is not finished. This means that you need to implement an observer pattern to download each image only once and be notified when the image download has finished. In react-native-expo-image-cache, this is how the API looks like:
import {CacheManager} from "react-native-expo-image-cache";// Remote URIconst {uri} = this.props;CacheManager.cache(uri, localURI => this.setState({ uri: localURI }));
Below is the implementation of the observer:
static async cache(uri: string, listener: Listener): Promise<void> { const {path, exists} = await getCacheEntry(uri); // Is the image is already downloading, we just listen if (isDownloading(uri)) { addListener(uri, listener); // If it's not downloading and it exists, we serve it } else if (exists) { listener(path); // Else, we download the image and notify everyone when done } else { addListener(uri, listener); await FileSystem.downloadAsync(uri, path); notifyAll(uri, path); unsubscribe(uri); }}
Progressive image loading
Every-time an image URI is stored in the database, store it’s base64 preview with it. This will allow you to load the image super smoothly. Below is an example:
{ preview: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", uri: "https://firebasestorage.googleapis.com/v0/b/react-native-e.appspot.com/o/b47b03a1e22e3f1fd884b5252de1e64a06a14126.png?alt=media&token=d636c423-3d94-440f-90c1-57c4de921641"}
Now you can immediately display a blurred version of the preview and decrease the blur to 0 when the full version of the image is loaded. On iOS, the <BlurView> from ExpoKit conveniently supports the native animation driver. An Android however, it doesn't default to an animated opacity view. I made a pull request to BlurView.android.js in order to test a water and find out if the team would be open to have an implementation of <BlurView> that would be more symmetrical on both platforms. In the meantime you can implement your own. This is how it looks like in react-native-expo-image-cache:
// intensity is an Animated.Valueconst opacity = intensity.interpolate({ inputRange: [0, 100], outputRange: [0, 1]});{ Platform.OS === "ios" && ( <AnimatedBlurView tint="dark" style={computedStyle} {...{intensity}} /> )}{ Platform.OS === "android" && ( <Animated.View style={[computedStyle, { backgroundColor: "rgba(0, 0, 0, 0.5)", opacity }]} /> )}
There is a serious bug in <Image>
This one. You might be tempted to set a URI in the state of your image component: set it to the preview data URI and then to the full image when loaded. Problem is, sometimes the image won’t refresh. You can use key to force its refresh but it will flicker. Solution? Superpose the full image to the preview. Again, this is how it looks like in react-native-expo-image-cache:
{ // If show the preview if it exists hasPreview && ( <RNImage source={{ uri: preview }} resizeMode="cover" style={computedStyle} /> )}{ // If the image is loaded, we show it on top // this.onLoadEnd is used to start the deblurring animation (uri && uri !== preview) && ( <RNImage source={{ uri }} resizeMode="cover" style={computedStyle} onLoadEnd={this.onLoadEnd} /> )}
That’s all Folks!
We will never finish to talk about Images in React Native. This is my top 5 list. Am I missing some items? Please let know and in the meantime, Happy Hacking 🎉
Looking for beautiful UI kits? I’m implementing all screens and components from Sketch Elements in React Native. You can get the preview here. I’m also trying to post live coding sessions and tutorials on my Youtube channel.
5 Things to know about Images React Native was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.