So I have this basic network image component. It will probably look similar to the one in the Image Component documents. The question is that when I switch the url, for the image, the image itself will not change to the new one, although it seems to be calling the render function again.
Device: iOS
Using: Mac
React-Native: 0.26.3
import React from 'react'
import {
View,
Image
} from 'react-native'
const NetworkImage = React.createClass({
getInitialState() {
return {
source: this.props.source
}
},
componentWillReceiveProps(newProps) {
if (newProps.source !== this.props.source) {
this.setState({
source: newProps.source
})
}
},
render() {
console.log('source: ', this.props)
return (
<Image
style={this.props.style}
source={this.state.source}
onLoad={() => {
console.log('loaded image!')
}}
onLoadStart={() => {
console.log('load starting')
}}/>)
}
})
module.exports = NetworkImage
I've experienced that same issue. Try adding a key={this.state.source.uri}
property to the image
@npomfret this solution works for me
@npomfret unfortunately the solution didn't work for me. What ended up working was putting a timeout around setState
within the componentWillReceiveProps
. Not the most ideal solution :(
Code:
import React from 'react'
import {
Image
} from 'react-native'
const TimerMixin = require('react-timer-mixin')
const NetworkImage = React.createClass({
mixins: [TimerMixin],
getInitialState() {
return {
source: this.props.source
}
},
componentWillReceiveProps(newProps) {
if (newProps.source.uri !== this.props.source.uri) {
this.setTimeout(() => {
this.setState({
source: newProps.source
})
}, 100)
}
},
render() {
return (
<Image
style={this.props.style}
source={this.state.source}
onLoad={() => {
console.log('loaded image!')
}}
onLoadStart={() => {
console.log('load starting')
}}/>)
}
})
module.exports = NetworkImage
How strange! This feels like a fairly serious bug. Can you reproduce it? What might be helpful is a stand alone git repo that illustrates the problem.
@facebook-github-bot label Icebox
Hi there! This issue is being closed because it has been inactive for a while.
But don't worry, it will live on with ProductPains! Check out its new home: https://productpains.com/post/react-native/image-component-will-not-update-correctly-when-passing-in-new-url
ProductPains helps the community prioritize the most important issues thanks to its voting feature.
It is easy to use - just login with GitHub.
Also, if this issue is a bug, please consider sending a PR with a fix.
We're a small team and rely on the community for bug fixes of issues that don't affect fb apps.
@facebook-github-bot close
@charpeni tells me to close this issue. If you think it should still be opened let us know why.
@npomfret I learned about the bug the hard way 馃槄 . It quite a serious one that probably should be reopened.
@wcandillon done. Can you create a replication of the bug on Snack? https://snack.expo.io/
@Charpeni: I wrote a snack here: https://snack.expo.io/@wcandillon/progressive-image-loading if you use such component (where uri is in the state and we change the value of the RN Image source) on a large collection of images, sometimes it will not refresh the image (5% of the time). Using the workaround above with key
solves the issue but to creates a flicker in the image.
The way I was able to work around this issue to to superpose the new Image component on top of the old one instead.
It is not restricted to changing the URI. Even if I change the image at the same URI, it still loads the previously placed image. I'll soon enough put reproduction steps. If I use Google Postman to do a simple GET request to the URI, I get the updated image. But Image component still loads the old image.
I looked into it a lot. As it turns out, React native does not even send a GET request to the server for the image. Which makes me think that it is caching the image somewhere.
I was going through react native node modules and in react-native->Libraries->Image->ImageSource.js, following is defined.
`/**
Copyright (c) 2015-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
@providesmodule ImageSource
@flow
*/
'use strict';
// This is to sync with ImageSourcePropTypes.js.
type ImageURISource = {
uri?: string,
bundle?: string,
method?: string,
headers?: Object,
body?: string,
cache?: 'default' | 'reload' | 'force-cache' | 'only-if-cached',
width?: number,
height?: number,
scale?: number,
};
export type ImageSource = ImageURISource | number | Array;
`
Which makes me think that there is prop called 'cache', possible values to which are given above. I added to source prop like follows.
According to its definition, it should always reload the image from the server and not the cache. But it is not working.
its a serious issue. i am facing it too
@shohailahm I discuss a workaround for this bug in the following medium story: https://hackernoon.com/5-things-to-know-about-images-react-native-69be41d2a9ee
@wcandillon without expo there isnt any workaround?
@shohailahm It might sound super hacky but the T workaround is to superpose new images on top of the "old" ones. This doesn't depend on expo. You can find a example here: https://github.com/wcandillon/react-native-expo-image-cache/blob/master/src/Image.js#L86
found a solution by adapting the react native source code handling the loading of image, code below is for iOS as that is what I need for now, have not tried on Android as i think the source code handling loading of image different for both platform:
If you are loading another image file from your local assets:
Add this somewhere in your code
const resolveAssetSource = require('resolveAssetSource');
Then at the point that you need to load another image using the same component, do the following:
let maps = [resolveAssetSource(new_local_image_name)];
this.refs["reference_string_to_your_image_component"].setNativeProps({source: maps});
If you are loading another image from the network, add the following codes at the point that you need to load the image using the same component:
maps = [{uri: "https://network_address_to_the_image", width: image_width_int, height: image_height_int}];
this.refs["reference_string_to_your_image_component"].setNativeProps({source: maps});
When all other solutions didn't work for us ... we tried changing http to https and it worked perfectly without needed to add key.
Make sure that you are reading from https when running on iOS.
Hey folks is this issue still open? and May I take it? Thanks
I haven't had much time to dig into this issue further, but I've been able to avoid this by using https://github.com/DylanVann/react-native-fast-image. I understand that this isn't an ideal solution either, but if you need a recommendation...
I couldn't reproduce this. Maybe it's no longer an issue?
I couldn't reproduce this. Maybe it's no longer an issue?
Still having this issue on 0.57.4
Edit: Please disregard this comment, I found another bug in my code that caused similar symptoms, everything seems to be working.
I am using mbox. I have a state called imageUri as state inside the component. And inside the render function. I put it inside a Image component like this
<Image style={{ width: deviceWidth, height: deviceHeight}} source={{ uri: this.imageUri }}
/>
however, When i change this.imageUri. the image it self can not be rendered on the screen.
Any idea?
Still an issue. Using key={this.state.source.uri}
fixes it though.
Still an issue. It's hard to tell just how much of the Image API is fundamentally broken.
Yep. The image component has been broken since 2016.
I have put this on the side for a while, but will be investigating this and working on it
on the following days Sorry for the delayed
Was this issue ever completed or is everyone just using key={this.state.source.uri}
as a workaround?
@wagnermaciel key props doesn't work in my case :/
There are some steps, to tackle this issue
Adding key to Image component
<Image key={state.imageUri} ...
Convert to http into https url
from <Image source={{uri : "**http**://yourweb/yourprofile.png"}} />
into
Add Cache options
<Image source={{uri : myImage, cache: 'reload'}} />
@wagnermaciel It works for me https://github.com/facebook/react-native/issues/12606#issuecomment-549231175 hope it helps.
I ran into the same issue when I was setting the image through state in componentDidMount. What worked for me is moving the image fetch to the render.
I fixed my issue by calling a helper in render() to set the image path and using that image constant instead of state. Works for me, all other solutions didn't work.
I've experienced that same issue. Try adding a
key={this.state.source.uri}
property to the image
Dude, I love you!!!
Thanks!
I can't believe the image component has had this issue since 2016 and still isn't fixed.
Yeap and this is very pity situation
I've been working with this issue for over a day. I'm trying to overwrite user profile photo's, but on android, I actually need to close the app and re open it for the image to change. Changing keys doesn't even work.
The RN image component has been fundamentally broken since 2016. I don't think it's ever getting fixed. Maybe there's an alternative implementation out there?
Still broken on RN 61, even after adding the key prop, cache="reload", and converting http to https.
Still have the same problem, adding key, cache didn't help
I think I've been able to reproduce this issue in a new Snack, here:
https://snack.expo.io/@rundbom/image-should-update
By using lorem picsum as a source a new remote image is available on each request to the same URI.
We force the image to rerender by updating the key prop.
The image doesn't change even though cache: 'reload'
is used.
This might be expected behaviour though?
One idea on fixing this (which I could send a PR on) would be to have request.cachePolicy
impact if a cached image is used in RCTImageLoader._loadImageOrDataWithURLRequest
. Code location:
https://github.com/facebook/react-native/blob/93e7a7a70dc2f41fccd3c1e4cce80d92913c4243/Libraries/Image/RCTImageLoader.mm#L486-L487
Would be glad to help out on this issue!
Guys just simply assign
Guys just simply assign
with a different key. Every time the screen rerendered if it found key is a new one it will rerender this component again even it has the same URL.
So, my example in Snack is contradicting exactly this. Given the same URL a new key will not "reload" the image (the component will be rerendered but the image won't be refetched). Tampering with the URL will reload the image. This is however in contradiction with the title of this issue, so it might be OT (the discussion have been talking about this case for a while though)?
On IOS the image component seems to have support for the cache: 'reload'
setting. The native code doesn't seem to do anything to support that setting though. So my question was if the IOS specific code should respect the setting, or maybe if the setting should be removed or documented as not working in this case?
@tobiasr In that case, is there any possibility to fix it by adding? new Date() right after the image URL. Something like that https://image/image.jpg?${new Date()}
@BruceSuperProgramer That will fix the issue.
For me, the question is regarding this documentation for IOS:
https://reactnative.dev/docs/images#cache-control-ios-only
My Snack, too me, is proving that these settings (at least cache: 'reload'
) have no effect on the load behaviour of the data on the other side of the URI.
So either an issue should be fixed or perhaps the settings should be removed/documented as not working?
@tobiasr In that case, is there any possibility to fix it by adding? new Date() right after the image URL. Something like that
https://image/image.jpg?${new Date()}
Worked for me
source={{
uri: REST_ENDPOINT_BASE + "/document-view/sample.jpg?date=" + moment().valueOf()
cache: "reload",
headers: {
Pragma: "no-cache",
}
@tobiasr In that case, is there any possibility to fix it by adding? new Date() right after the image URL. Something like that
https://image/image.jpg?${new Date()}
Worked for me
source={{ uri: REST_ENDPOINT_BASE + "/document-view/sample.jpg?date=" + moment().valueOf() cache: "reload", headers: { Pragma: "no-cache", }
I think it it should work without cache: "reload" as well, right? As I've tried to explain above, that setting isn't used on the image component.
Even I'm facing this issue and any of the above solutions did not help me in any way. The Text component is printing proper URI during each render but the image still shows up the same.
{thumbnails.map((thumbnail) => (
<View>
<TouchableOpacity onPress={() => setSelectedThumbnail(thumbnails[index])}>
< Image key={thumbnail} source={{ uri: thumbnail, cache: "reload",
headers: {
Pragma: "no-cache",
} }} style={{ width: 30, height: 30, marginLeft: 10 }} />
</TouchableOpacity>
<Text key={thumbnail} style={{fontSize:7}}>{thumbnail}</Text>
</View>
))}
Please look at the image and its URI.
Note: The image is rendering properly when i just make any small change and expo refresh the page.
Happy Friday,
I might have a solution - but it ain't pretty...
After being severely p*ed off by this problem the past few days and trying everything from cache: reload and different image libraries like fast-image to no avail I happened to make an important observation after my [what felt like] 1000th time of trying to overcome this tenacious little bug.
I noticed that if I quickly dismounted and re-mounted the component which contained the Image component that the original image would load - this didn't stack up with my original hypothesis (shared by many on this thread) that unmounting and remounting was causing the image component to work as expected.
So, instead of setting my image's URI to the prop which I passed into my component I set it to a state variable. I then setup a useEffect hook which would execute whenever the URI prop changed - but instead of immediately updating the state I used the setTimeout function and updated the state's copy of the URI after a few seconds ... and it worked as expected.
Most helpful comment
I've experienced that same issue. Try adding a
key={this.state.source.uri}
property to the image