diff --git a/packages/react-native-web/src/exports/Image/__tests__/index-test.js b/packages/react-native-web/src/exports/Image/__tests__/index-test.js
index 5aa8d334..b9dfa9ae 100644
--- a/packages/react-native-web/src/exports/Image/__tests__/index-test.js
+++ b/packages/react-native-web/src/exports/Image/__tests__/index-test.js
@@ -5,8 +5,8 @@ import Image from '../';
import ImageLoader from '../../../modules/ImageLoader';
import ImageUriCache from '../ImageUriCache';
import React from 'react';
+import { shallow } from 'enzyme';
import StyleSheet from '../../StyleSheet';
-import { mount, shallow } from 'enzyme';
const originalImage = window.Image;
@@ -121,22 +121,18 @@ describe('components/Image', () => {
});
test('is called on update if "uri" is different', () => {
- jest.useFakeTimers();
const onLoadStub = jest.fn();
const uri = 'https://test.com/img.jpg';
- const component = mount();
+ const component = shallow();
component.setProps({ source: 'https://blah.com/img.png' });
- jest.runOnlyPendingTimers();
expect(onLoadStub.mock.calls.length).toBe(2);
});
test('is not called on update if "uri" is the same', () => {
- jest.useFakeTimers();
const onLoadStub = jest.fn();
const uri = 'https://test.com/img.jpg';
- const component = mount();
+ const component = shallow();
component.setProps({ resizeMode: 'stretch' });
- jest.runOnlyPendingTimers();
expect(onLoadStub.mock.calls.length).toBe(1);
});
});
@@ -185,7 +181,7 @@ describe('components/Image', () => {
ImageUriCache.add(uriTwo);
// initial render
- const component = mount();
+ const component = shallow();
ImageUriCache.remove(uriOne);
expect(
component
@@ -206,11 +202,9 @@ describe('components/Image', () => {
});
test('is correctly updated when missing in initial render', () => {
- jest.useFakeTimers();
const uri = 'https://testing.com/img.jpg';
- const component = mount();
+ const component = shallow();
component.setProps({ source: { uri } });
- jest.runOnlyPendingTimers();
expect(
component
.render()
@@ -218,6 +212,19 @@ describe('components/Image', () => {
.attr('src')
).toBe(uri);
});
+
+ test('is correctly updated only when loaded if defaultSource provided', () => {
+ const defaultUri = 'https://testing.com/preview.jpg';
+ const uri = 'https://testing.com/fullSize.jpg';
+ let loadCallback;
+ ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
+ loadCallback = onLoad;
+ });
+ const component = shallow();
+ expect(component.find('img').prop('src')).toBe(defaultUri);
+ loadCallback();
+ expect(component.find('img').prop('src')).toBe(uri);
+ });
});
describe('prop "style"', () => {
diff --git a/packages/react-native-web/src/exports/Image/index.js b/packages/react-native-web/src/exports/Image/index.js
index 5695ecd9..2262a68e 100644
--- a/packages/react-native-web/src/exports/Image/index.js
+++ b/packages/react-native-web/src/exports/Image/index.js
@@ -177,11 +177,14 @@ class Image extends Component<*, State> {
componentDidUpdate(prevProps) {
const prevUri = resolveAssetUri(prevProps.source);
const uri = resolveAssetUri(this.props.source);
+ const hasDefaultSource = this.props.defaultSource != null;
if (prevUri !== uri) {
ImageUriCache.remove(prevUri);
const isPreviouslyLoaded = ImageUriCache.has(uri);
isPreviouslyLoaded && ImageUriCache.add(uri);
- this._updateImageState(getImageState(uri, isPreviouslyLoaded));
+ this._updateImageState(getImageState(uri, isPreviouslyLoaded), hasDefaultSource);
+ } else if (hasDefaultSource && prevProps.defaultSource !== this.props.defaultSource) {
+ this._updateImageState(this._imageState, hasDefaultSource);
}
if (this._imageState === STATUS_PENDING) {
this._createImageLoader();
@@ -379,8 +382,8 @@ class Image extends Component<*, State> {
}
_onLoadStart() {
- const { onLoadStart } = this.props;
- this._updateImageState(STATUS_LOADING);
+ const { defaultSource, onLoadStart } = this.props;
+ this._updateImageState(STATUS_LOADING, defaultSource != null);
if (onLoadStart) {
onLoadStart();
}
@@ -390,11 +393,12 @@ class Image extends Component<*, State> {
this._imageRef = ref;
};
- _updateImageState(status) {
+ _updateImageState(status: ?string, hasDefaultSource: ?boolean = false) {
this._imageState = status;
const shouldDisplaySource =
- this._imageState === STATUS_LOADED || this._imageState === STATUS_LOADING;
- // only triggers a re-render when the image is loading (to support PJEG), loaded, or failed
+ this._imageState === STATUS_LOADED ||
+ (this._imageState === STATUS_LOADING && !hasDefaultSource);
+ // only triggers a re-render when the image is loading and has no default image (to support PJPEG), loaded, or failed
if (shouldDisplaySource !== this.state.shouldDisplaySource) {
if (this._isMounted) {
this.setState(() => ({ shouldDisplaySource }));