i'm new in smartphones app developer, so i have this trouble, I'm trying to optimize my application by trying to store the cache images, however, by performing the save action on the device these are not shown, but it shows me in the debug that if they are stored but I can not see them, they are invisible...
Without Cache
Cache stored
With react-native you can't do this because when you require an image from a path, this path has to be a fixed string. You cannot do, for example:
const myImage = require(`/cache/${imageId}.png`);
Anyway, network images are already cached AFAIK.
Related
What am I doing?
A react-native-video component is loaded into the screen with a source uri from my nodejs backend.
What is the problem? (Only tried on android)
My backend is working fine and the video is loaded, but extremely slow. I checked on the backend that the video component is requesting a byte-range of 1MB every ~1s. On the other hand, if I request the video ranges with axios, it takes a couple of ms to request multiple byte-ranges.
When using a video stored locally on the android device, the loading time is almost instantaneous.
I tried the default android player as well as exoplayer with no difference in loading times.
I am trying all this with only one Video component and when I comment it the app runs smoothly
Possible solution:
I don't want to load the data directly from the Video component and I am trying now to download the byte-ranges and store them locally. Later I plan to load these byte-ranges into the Video component.
import AsyncStorage from '#react-native-async-storage/async-storage';
...
await AsyncStorage.setItem(video_name, JSON.stringify(byte_range_data_from_backend))
This works fine and I can read the byte_range_data_from_backend later with:
const data_from_item = await AsyncStorage.getItem(video_name)
What is my question?
How can I get these video_ranges uris to pass them to the Video component?
I think I need to create some kind of file and update the file content every time I receive a new byte-range. Meanwhile, I would like the video to be played using the already downloaded byte-ranges.
Is this possible or is not a good approach? What would be a possible way to load videos fast? It would be nice to download some byte-ranges before even trying to play the video, so that the waiting time for the user is minimal.
I'm using RNCamera to take a picture. The path to the picture taken is in the file systems cache. Something like this:
"file:///data/user/0/com.find/cache/Camera/1986b5f9-4770-a255-543703fc6597.jpg"
Then I use the react native image editor to crop this image and I get another file. Something like this:
"file:///data/user/0/com.find/cache/ReactNative_cropped_image_8510242.jpg"
These files are (according to the filepath of the images, at least) stored in the cache on the phone.
My question is this:
How long can I be sure that these images will remain in the cache? Do they get cleared when the app is closed? Or will they remain until I delete them myself?
Thanks!
This Thread is old but for those who need it:
So, i've been working with RNCamera since 2 weeks now and i had the same question, but sadly i couldn't find any answer. I now checked with react-native-fs and it seems like the images are stored for the whole Camera session or maybe even the whole app session, thats the thing i could not find out.
But they still stay cached after reusing the RNCamera
I'm losing my mind trying to get this to work.
So, it seems that, in React Native, Android will cache the image of a certain URL forever. If I change the image at that URL, it will not change in the app for Android, but iOS handles it just fine.
I know about the trick of just adding
`?time=${Date.now()}`
to the end of the uri specified in source={{ uri }}
However, that will fetch a new image every time, which technically works, but then the user has to wait for the image to load every time. I could add an ActivityIndicator placeholder while the image loads, but if I could properly cache the image then that ActivityIndicator wouldn't be shown nearly as often, making for better UX.
I would like to know if there's a way to check if the remote image has changed, within the constraints of Expo SDK 33 (no react-native link). I can handle the cache busting just fine if there is such a method, it would just require incrementing a persistently saved integer whenever a change is detected, and appending that to the uri.
Maybe a different approach is necessary.
I fixed this issue in the backend. If you have access to the backend, that's great!
What I did was create an API that would take in the path to the image that I wanted, and it redirected to that image, with ?lastUpdated=<modified> appended to the URL, where <modified> is the time at which that file was last modified. This way, it automatically cache busts the image whenever the image is changed!
I have a component which consists of a FlatList and a Modal-component. This modal component has several Image-components. The images are set by the source-attribute to an external url.
I switch die visibility of the modal-component by changing the visible attribute.
The problem:
Everytime I open the modal (at the beginning or after closing it) the images are loaded from the server. So there are no images for maybe 1 second.
Are the images deleted from the cache if I set the visible of the modal to false??
Caching of images can be related to multiple things. The most effective one is probably the Cache-Control header sent from the server when you request the image. You can check the headers to see if the request has a low time on cache.
The other thing is that, while development process, building or hot-reloading of the app can result in clearing the cache for the app.
Another reason can be the low storage in device might be triggering the OS to delete cached images.
In iOS you can control caching. More info can be find here.
Its hard to tell without any sample code but, if you are mounting and then unmounting Modal when you set the visibility of it, you can try to prefetch images before mounting the Modal. If the caching control is right when you mount the Modal they should be served from the cache. If the images you are trying to show are large it might be a performance issue or they might be taking long time to load from the disk. You can debug this with a less number of item in modal with smaller images.
Hope the information above is going to be enough.
you can use react-native-img-cache
or react-native-cached-image to cash your images
and yes the images in react native are not cached by default
also to preload images you can use react-native-fast-image
I am having difficulties to understand Image prefetch. In the doc's there is not much explanation about it:
"Prefetches a remote image for later use by downloading it to the disk
cache"
Could you please help me understand the following about Image prefetch:
Suppose a user uploads a profile image, and the image's URL is stored in the AsyncStorage.
Should I run Image.prefetch(UserStore.profileImageUrl) only once after successful upload. And use prefetched image in the components normally like <Imagesource={{uri: UserStore.profileImageUrl}}/>
Or should I always run Image.prefetch(UserStore.profileImageUrl) before using that image in the component, then only run <Imagesource={{uri: UserStore.profileImageUrl}}/>
Suppose, later on, the user changes their profile image by uploading a new image and after successful upload, I will prefetch the new image. Will the previously cached image still exist on the disk?
If yes, won't it occupy a lot of space in the device if there are lots of prefetched images?
Is there any way to manually remove the prefetched image from the disk?
With the above questions in mind, if there are alternate solutions to achieve caching of images when using react native with expo, could you please help me with it.
It was indeed a question that I was dealing with for a while, and I learned a few things about Image.prefetch:
In the current React-Native version (0.48), this method is still in progress. To be more precise:
the ios implementation is still incomplete.
There is no complete guide on it.
There is no way to clear cache (you can check if the url is cached, however as far as I know you cannot clear it now).
As a result, I don't suggest you use it. Regardless, if you want to know how the API works, it is how:
Purpose
The purpose is quite obvious I think, this API:
Prefetches a remote image for later use by downloading it to the disk cache
It means that you can use Image.prefetch(url) in your constructor or componentWillMount. It tries to fetch image asynchronically, then, render your page with some kind of an ActivityIndicator, Finally, when the image is successfully fetched you can re-render your component.
Image.prefetch(url) actually saves the image to disk (not memory), as a result, whenever or wherever you try to use
<Image source={{uri:url}}/>
At firsts it checks the list of caches urls, if you have prefetched that url before (and it is located on the disk), it won't bother to re-fetch (unless you run function `Image.prefetch(url)' again (I am not sure if it works properly).
The implications of this issue are so complicated. It means that if you prefetch an image inside one component (for example <Component1/>), when you try to show this specific image in another component (for example <Component12>), It won't fetch the image and just uses the disk cache.
Therefore, either don't use this Image.prefetch at all (until there is a complete API, with cache control) or use it at your own risk.
on Android
On Android, you have 3 APIs for prefetch, and only one of them is presented in the documentation:
prefetch:
var response = Image.prefetch(imageUrl,callbackFunction)
Image.prefetch can have an optional second argument callbackFunction, which a function that runs Before fetching image. It can be written in the following format:
var response = Image.prefetch(imageUrl,()=>console.log('Image is being fetched'))
It might be worthy to note that, callbackFunction can have an argument called requestId, (indicating the number of prefetch among all other prefetches) which can be then used to abort the fetch.
var response = Image.prefetch(imageUrl,(id)=>console.log(id))
Moreover, response is a promise, you can use .then to do more after the image is pre-fetched.
abortPrefetch
Image.abortPrefetch(requestId) ;
used to abort the pending prefetch. requestId used as argument is the same as the one seen in prefetch.
queryCache
Image.queryCache([url1,url2, ...])
.then((data)=>console.log(data));
Used to check if a certain url is already cached, and if so where is it cached (disk or memory)
on IOS
I think that only Image.prefetch(url) is currently available on IOS, and there is no callback function to be called as the second argument.
if there are alternate solutions to achieve caching of images when
using react native with expo, could you please help me with it.
You may be interested in my higher order component module that adds performance related image caching and "permanent cache" functionality to the native <Image> component.
React Native Image Cache HOC
Tl;DR Code Example:
import imageCacheHoc from 'react-native-image-cache-hoc';
const CacheableImage = imageCacheHoc(Image);
export default class App extends Component<{}> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<CacheableImage style={styles.image} source={{uri: 'https://i.redd.it/rc29s4bz61uz.png'}} />
<CacheableImage style={styles.image} source={{uri: 'https://i.redd.it/hhhim0kc5swz.jpg'}} permanent={true} />
</View>
);
}
}
The first image will be cached until the total local cache grows past 15 MB (by default) then cached images are deleted oldest first until total cache is below 15 MB again.
The second image will be stored to local disk permanently. People use this as a drop in replacement for shipping static image files with your app.
Personally I would not overcomplicate things by writing over files over and over when the file changes, that's just asking for a massive headache. Instead I would create a unique filename for each upload. So the user's profile pic the first time they upload is "profile-uniqueIdHere.jpg" and when they change their profile pic you just create a new file "profile-anotherUniqueIdHere.jpg" and update their user data to reflect the new file location. For help with creating unique Ids look at react-native-uuid.