mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-26 15:58:28 +00:00
[add] Image.queryCache API
Image.queryCache is a React Native method that allows the user to see if a given uri is in the cache. It specifies three return options: disk, memory or both. Choosing both seemed most appropriate since we don't really know and can't confirm. The way Image is implemented, if RNW thinks the image might already be loaded, it displays it immediately. Otherwise there can be a flash of a frame. In some scenarios, if the user chooses to preload and then make an Image element, it would still flash. By adding it to the cache, we can prevent that. Close #1344
This commit is contained in:
committed by
Nicolas Gallagher
parent
39d2e18ccf
commit
950bfd039c
@@ -14,6 +14,7 @@ const findImageSurfaceStyle = wrapper => StyleSheet.flatten(wrapper.childAt(0).p
|
||||
|
||||
describe('components/Image', () => {
|
||||
beforeEach(() => {
|
||||
ImageUriCache._entries = {};
|
||||
window.Image = jest.fn(() => ({}));
|
||||
});
|
||||
|
||||
@@ -111,8 +112,8 @@ describe('components/Image', () => {
|
||||
});
|
||||
const onLoadStub = jest.fn();
|
||||
const uri = 'https://test.com/img.jpg';
|
||||
shallow(<Image onLoad={onLoadStub} source={uri} />);
|
||||
ImageUriCache.add(uri);
|
||||
shallow(<Image onLoad={onLoadStub} source={uri} />);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(ImageLoader.load).not.toBeCalled();
|
||||
expect(onLoadStub).toBeCalled();
|
||||
@@ -164,6 +165,19 @@ describe('components/Image', () => {
|
||||
expect(component.find('img')).toBeUndefined;
|
||||
});
|
||||
|
||||
test('is set immediately if the image was preloaded', () => {
|
||||
const uri = 'https://yahoo.com/favicon.ico';
|
||||
ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
onLoad();
|
||||
});
|
||||
return Image.prefetch(uri).then(() => {
|
||||
const source = { uri };
|
||||
const component = shallow(<Image source={source} />, { disableLifecycleMethods: true });
|
||||
expect(component.find('img').prop('src')).toBe(uri);
|
||||
ImageUriCache.remove(uri);
|
||||
});
|
||||
});
|
||||
|
||||
test('is set immediately if the image has already been loaded', () => {
|
||||
const uriOne = 'https://google.com/favicon.ico';
|
||||
const uriTwo = 'https://twitter.com/favicon.ico';
|
||||
@@ -247,4 +261,17 @@ describe('components/Image', () => {
|
||||
const component = shallow(<Image onResponderGrant={fn} />);
|
||||
expect(component.prop('onResponderGrant')).toBe(fn);
|
||||
});
|
||||
|
||||
test('queryCache', () => {
|
||||
const uriOne = 'https://google.com/favicon.ico';
|
||||
const uriTwo = 'https://twitter.com/favicon.ico';
|
||||
ImageUriCache.add(uriOne);
|
||||
ImageUriCache.add(uriTwo);
|
||||
return Image.queryCache([uriOne, uriTwo, 'oops']).then(res => {
|
||||
expect(res).toEqual({
|
||||
[uriOne]: 'disk/memory',
|
||||
[uriTwo]: 'disk/memory'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+16
-1
@@ -130,7 +130,22 @@ class Image extends Component<*, State> {
|
||||
}
|
||||
|
||||
static prefetch(uri) {
|
||||
return ImageLoader.prefetch(uri);
|
||||
return ImageLoader.prefetch(uri).then(() => {
|
||||
// Add the uri to the cache so it can be immediately displayed when used
|
||||
// but also immediately remove it to correctly reflect that it has no active references
|
||||
ImageUriCache.add(uri);
|
||||
ImageUriCache.remove(uri);
|
||||
});
|
||||
}
|
||||
|
||||
static queryCache(uris) {
|
||||
const result = {};
|
||||
uris.forEach(u => {
|
||||
if (ImageUriCache.has(u)) {
|
||||
result[u] = 'disk/memory';
|
||||
}
|
||||
});
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
_filterId = 0;
|
||||
|
||||
Reference in New Issue
Block a user