-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
setState warnings, Broken Images, & Race Conditions #33
Conversation
PR for the patch in jayesbe#22
…fixes; Fixes lots of race conditions
@nbolender Nice work. I've started using your this branch in my project, and it is a big improvement, but there still seems to be something causing a I'm not sure how to figure out where the warning is being triggered though. Any tips on tracing the exact bit of code? |
@robwalkerco I believe there is still one possibility for a setState warning in the If you can reproduce it consistently, you might try commenting out the setState statement in the completion handler to see if it is in there. If that's indeed the issue, it might be best to drop the imageDownloadProgress callback altogether, then perform the same check in the download completion handler as we do in its error handler. |
@nbolender great work. This is very much appreciated. I will go through this soon and Im sure it will be merged by the end of the week. |
@nbolender I've isolated the warning to the I'll try to figure out more tomorrow, but it seems to happen when you first mount a page containing cachable images, then unmount, then mount the same page again. The images are displayed fine, but the warning occurs. |
@nbolender I've not managed to figure out the exact cause of warning for me yet, and why it consistently occurs
and using |
Any news about merging this one? |
I've stopped using this package now, as I was still having issues that were only fixed by my hacky work around :( This PR was an improvement though, so I think it would be helpful if merged. |
Sorry guys have been a little behind. Please create new issues if / when they come up :) |
Hm @robwalkerco tested your PR having the same issues as before. Had to switch to https://github.com/kfiroo/react-native-cached-image :-( |
This PR potentially resolves:
Summary of fixes:
setState
warnings.There is also a possibility that if you render many images that need to be downloaded, and then cause the jobs to be cancelled (for example, by navigating to a different screen), you may get an error from React Native of the form "Callback with id #: undefined.undefined() not found". This is caused by RNFS itself and I have a PR set up here: itinance/react-native-fs#219
Here is a walkthrough of the code changes:
Merged in @jayesbe’s changes in the comments of Issue setState warning #22 (setState warning), with some help from @robwalkerco.
downloading
andjobId
are not used in the render functions, and a race condition can cause these to be out of date when usingthis.setState()
because it is asynchronous. These have been moved out of the state object._processSource()
was erroneously triggering a re-download even when the source URI was identical. Any re-renders in the parent component, or change in network state, were causing the download to be restarted. Comparing the URI property (when present) saves us from accidentally downloading the same image twice.I have re-added a file size check in
checkImageCache()
. This is necessary because on iOS, RNFS creates a zero-byte file when it begins the download. In my application, sometimes a component uses the same URI as another CacheableImage instance. There was a situation where the first component began downloading, and the second one saw the empty file and displayed a blank image. React Native does not update the image when it is changed on disk, so it rendered as transparent.The file size check throws an error if there is a zero-byte file, whether it is still downloading or sometime else caused the download operation to not complete. The error starts a new download. An alternative to this functionality could be to first download the image to a random temporary location until it is completed downloading, but you still might find a race condition while the file is being moved to the final location. Also, that alternative could still result in two downloads of the same image.
Ideally, RNFS would check to see if it is already downloading a URI, and bind the two jobs into one. But I think this is an edge case overall.
Fixed a typo in
RNFS.mkdir().then()
(_deleteFilePath()
)Added a check to stop an in-progress download before starting a new one in the same component.
RNFS.downloadFile()
immediately returns thejobId
, so I captured that synchronously. Without this, a race condition exists where the component might unmount beforeimageDownloadBegin()
is called, and thus won’t cancel the download job. This can cause a setState warning, not to mention a waste of bandwidth.Because RNFS throws an error when you call
stopDownload()
, I added a check in the error handler to avoid a setState warning. (We only callstopDownload()
on unmount) It is still necessary to call_deleteFilePath()
on an error or cancelled download, because RNFS does not remove a partially-downloaded file when this happens._handleConnectivityChange()
is now unset incomponentWillUnmount()
, and its status is checked in the initial NetInfo fetch. This solves an issue where a component will quickly mount and then unmount before the initial fetch is resolved. Without this, you may see setState warnings especially if you use local images and accidentally keepprops.checkNetwork == true
.