[Android] Calling setNativeProps triggers Image load callbacks
See original GitHub issueWhen calling imageRef.setNativeProps(...)
on Android, it triggers some callback methods, like onLoad
, onLoadStart
, etc. Only on Android and not on iOS/Web. It should not trigger these methods.
Explaining what this bug has caused
At the DevHub App, while the transparent images are loading, they have a discrete background color, like a placeholder. When they finish loading, I apply a #FFFFFF
background. Because of this bug, when calling setNativeProps
on onLoadEnd
it would trigger another onLoadStart
which would trigger another setNativeProps
which would trigger another onLoadEnd
and so on. This infinite loop was the cause of severe performance issues on Android, like this one: https://github.com/react-spring/react-spring/issues/570. I’m glad I finally found out the root cause!
I was able to detect this because I noticed the images on some android devices were blinking for apparently no reason (hint: there is always a reason)
React Native version: 0.59.8
Environment
React Native Environment Info: System: OS: macOS 10.14.5 CPU: (4) x64 Intel® Core™ i5-6267U CPU @ 2.90GHz Memory: 17.80 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 11.5.0 - /usr/local/bin/node Yarn: 1.15.2 - ~/.yarn/bin/yarn npm: 6.9.0 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2 Android SDK: API Levels: 19, 22, 23, 24, 25, 27, 28 Build Tools: 23.0.1, 23.0.3, 24.0.3, 25.0.0, 25.0.1, 25.0.2, 25.0.3, 26.0.0, 26.0.1, 26.0.2, 26.0.3, 27.0.0, 27.0.1, 27.0.2, 27.0.3, 28.0.0, 28.0.2, 28.0.3 System Images: android-19 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-Q | Google Play Intel x86 Atom IDEs: Android Studio: 3.4 AI-183.5429.30.34.5452501 Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild npmGlobalPackages: react-native-git-upgrade: 0.2.7 react-native-macos-cli: 2.0.1
Steps To Reproduce
<Image ref={imageRef} onLoad={() => { console.log('onLoad'); }} />
imageRef.current.setNativeProps({ style: { backgroundColor: 'red' } })
- Compare log between iOS and Android
Snack: https://snack.expo.io/@brunolemos/android-image-setnativeprops-onload
User-land workaround: https://github.com/devhubapp/devhub/commit/682cc69b9c7252b73acb070e5cbcacc348f081e2
See code
import React, { useEffect, useRef, useState } from 'react';
import { Button, Image, ScrollView, Text, View } from 'react-native';
export default function App() {
const imageRef = useRef(null);
const [logs, setLogs] = useState([]);
useEffect(() => {
log('MOUNT');
}, []);
function log(text) {
setLogs(l => [...l, text]);
}
function updateImageBg(color) {
if (!(imageRef && imageRef.current)) return;
imageRef.current.setNativeProps({
style: { backgroundColor: color },
});
}
return (
<View style={{ flex: 1, paddingTop: 40, alignItems: 'center' }}>
<Image
ref={imageRef}
onLoad={() => {
log('onLoad');
}}
source={{
uri:
'https://cdn4.iconfinder.com/data/icons/logos-3/600/React.js_logo-512.png',
}}
style={{ width: 100, height: 100 }}
/>
<View style={{ flexDirection: 'row' }}>
<Button
title="Green"
onPress={() => updateImageBg('green')}
style={{ flex: 1 }}
/>
<Button
title="Red"
onPress={() => updateImageBg('red')}
style={{ flex: 1 }}
/>
</View>
<ScrollView style={{ flex: 1 }}>
{logs.map((log, index) => (
<Text key={`log-${index}`}>{log}</Text>
))}
</ScrollView>
</View>
);
}


Issue Analytics
- State:
- Created 4 years ago
- Reactions:19
- Comments:10 (2 by maintainers)
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
This stale bot is a tad aggressive…