Skip to content

Commit 2c1bcba

Browse files
retyuifacebook-github-bot
authored andcommitted
feature: Update Image.getSize/getSizeWithHeaders methods to return a promise (#42895)
Summary: `Image.getSize/getSizeWithHeaders` are still working in old fashioned "callback" way ```tsx Image.getSize(uri, function success(width,height) { }, function failure(){ } ); // undefined Image.getSizeWithHeaders(uri, headers, function success(width,height) { }, function failure(){ } ); // undefined ``` But in 2024 more developers prefer use async/await syntax for asynchronous operations So, in this PR I added support for Promise API with **backward compatibility**, modern way: ```tsx Image.getSize(uri).then(({width,height}) => { }); // Promise Image.getSizeWithHeaders(uri, headers).then(({width,height}) => { }); // Promise ``` bypass-github-export-checks ## Changelog: [GENERAL] [ADDED] - `Image.getSize/getSizeWithHeaders` method returns a promise if you don't pass a `success` callback Pull Request resolved: #42895 Test Plan: 1. ts: New test cases added in typescript tests 2. runtime: you can create a new project and put code from this PR into the next files a. `node_modules/react-native/Libraries/Image/Image.android.js` b. `node_modules/react-native/Libraries/Image/Image.ios.js` Reviewed By: javache Differential Revision: D53919431 Pulled By: cipolleschi fbshipit-source-id: 508b201e17e0ffda2e67aa5292bf9906b88d09c5
1 parent 489df72 commit 2c1bcba

File tree

7 files changed

+74
-30
lines changed

7 files changed

+74
-30
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ module.exports = {
113113
files: ['**/*.d.ts'],
114114
plugins: ['redundant-undefined'],
115115
rules: {
116+
'no-dupe-class-members': 'off',
116117
'redundant-undefined/redundant-undefined': [
117118
'error',
118119
{followExactOptionalPropertyTypes: true},

packages/react-native/Libraries/Image/Image.android.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import {
2323
import {getImageSourcesFromImageProps} from './ImageSourceUtils';
2424
import {convertObjectFitToResizeMode} from './ImageUtils';
2525
import ImageViewNativeComponent from './ImageViewNativeComponent';
26-
import NativeImageLoaderAndroid from './NativeImageLoaderAndroid';
26+
import NativeImageLoaderAndroid, {
27+
type ImageSize,
28+
} from './NativeImageLoaderAndroid';
2729
import resolveAssetSource from './resolveAssetSource';
2830
import TextInlineImageNativeComponent from './TextInlineImageNativeComponent';
2931
import * as React from 'react';
@@ -40,13 +42,15 @@ function generateRequestId() {
4042
*/
4143
function getSize(
4244
url: string,
43-
success: (width: number, height: number) => void,
45+
success?: (width: number, height: number) => void,
4446
failure?: (error: mixed) => void,
45-
): void {
46-
NativeImageLoaderAndroid.getSize(url)
47-
.then(function (sizes) {
48-
success(sizes.width, sizes.height);
49-
})
47+
): void | Promise<ImageSize> {
48+
const promise = NativeImageLoaderAndroid.getSize(url);
49+
if (typeof success !== 'function') {
50+
return promise;
51+
}
52+
promise
53+
.then(sizes => success(sizes.width, sizes.height))
5054
.catch(
5155
failure ||
5256
function () {
@@ -64,13 +68,15 @@ function getSize(
6468
function getSizeWithHeaders(
6569
url: string,
6670
headers: {[string]: string, ...},
67-
success: (width: number, height: number) => void,
71+
success?: (width: number, height: number) => void,
6872
failure?: (error: mixed) => void,
69-
): void {
70-
NativeImageLoaderAndroid.getSizeWithHeaders(url, headers)
71-
.then(function (sizes) {
72-
success(sizes.width, sizes.height);
73-
})
73+
): void | Promise<ImageSize> {
74+
const promise = NativeImageLoaderAndroid.getSizeWithHeaders(url, headers);
75+
if (typeof success !== 'function') {
76+
return promise;
77+
}
78+
promise
79+
.then(sizes => success(sizes.width, sizes.height))
7480
.catch(
7581
failure ||
7682
function () {

packages/react-native/Libraries/Image/Image.d.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,20 +325,31 @@ export interface ImageProps extends ImagePropsBase {
325325
style?: StyleProp<ImageStyle> | undefined;
326326
}
327327

328+
export interface ImageSize {
329+
width: number;
330+
height: number;
331+
}
332+
328333
declare class ImageComponent extends React.Component<ImageProps> {}
329334
declare const ImageBase: Constructor<NativeMethods> & typeof ImageComponent;
330335
export class Image extends ImageBase {
336+
static getSize(uri: string): Promise<ImageSize>;
331337
static getSize(
332338
uri: string,
333339
success: (width: number, height: number) => void,
334340
failure?: (error: any) => void,
335-
): any;
341+
): void;
342+
343+
static getSizeWithHeaders(
344+
uri: string,
345+
headers: {[index: string]: string},
346+
): Promise<ImageSize>;
336347
static getSizeWithHeaders(
337348
uri: string,
338349
headers: {[index: string]: string},
339350
success: (width: number, height: number) => void,
340351
failure?: (error: any) => void,
341-
): any;
352+
): void;
342353
static prefetch(url: string): Promise<boolean>;
343354
static prefetchWithMetadata(
344355
url: string,

packages/react-native/Libraries/Image/Image.ios.js

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import type {ImageStyle, ImageStyleProp} from '../StyleSheet/StyleSheet';
1212
import type {RootTag} from '../Types/RootTagTypes';
1313
import type {AbstractImageIOS, ImageIOS} from './ImageTypes.flow';
14+
import type {ImageSize} from './NativeImageLoaderAndroid';
1415

1516
import {createRootTag} from '../ReactNative/RootTag';
1617
import flattenStyle from '../StyleSheet/flattenStyle';
@@ -29,29 +30,38 @@ import * as React from 'react';
2930

3031
function getSize(
3132
uri: string,
32-
success: (width: number, height: number) => void,
33+
success?: (width: number, height: number) => void,
3334
failure?: (error: mixed) => void,
34-
): void {
35-
NativeImageLoaderIOS.getSize(uri)
36-
.then(([width, height]) => success(width, height))
35+
): void | Promise<ImageSize> {
36+
const promise = NativeImageLoaderIOS.getSize(uri).then(([width, height]) => ({
37+
width,
38+
height,
39+
}));
40+
if (typeof success !== 'function') {
41+
return promise;
42+
}
43+
promise
44+
.then(sizes => success(sizes.width, sizes.height))
3745
.catch(
3846
failure ||
3947
function () {
40-
console.warn('Failed to get size for image ' + uri);
48+
console.warn('Failed to get size for image: ' + uri);
4149
},
4250
);
4351
}
4452

4553
function getSizeWithHeaders(
4654
uri: string,
4755
headers: {[string]: string, ...},
48-
success: (width: number, height: number) => void,
56+
success?: (width: number, height: number) => void,
4957
failure?: (error: mixed) => void,
50-
): void {
51-
NativeImageLoaderIOS.getSizeWithHeaders(uri, headers)
52-
.then(function (sizes) {
53-
success(sizes.width, sizes.height);
54-
})
58+
): void | Promise<ImageSize> {
59+
const promise = NativeImageLoaderIOS.getSizeWithHeaders(uri, headers);
60+
if (typeof success !== 'function') {
61+
return promise;
62+
}
63+
promise
64+
.then(sizes => success(sizes.width, sizes.height))
5565
.catch(
5666
failure ||
5767
function () {

packages/react-native/Libraries/Image/ImageTypes.flow.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ import typeof TextInlineImageNativeComponent from './TextInlineImageNativeCompon
1818
import * as React from 'react';
1919

2020
type ImageComponentStaticsIOS = $ReadOnly<{
21-
getSize: (
21+
getSize(uri: string): Promise<{width: number, height: number}>,
22+
getSize(
2223
uri: string,
2324
success: (width: number, height: number) => void,
2425
failure?: (error: mixed) => void,
25-
) => void,
26+
): void,
2627

28+
getSizeWithHeaders(
29+
uri: string,
30+
headers: {[string]: string, ...},
31+
): Promise<{width: number, height: number}>,
2732
getSizeWithHeaders(
2833
uri: string,
2934
headers: {[string]: string, ...},

packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4484,11 +4484,16 @@ exports[`public API should not change unintentionally Libraries/Image/ImageSourc
44844484

44854485
exports[`public API should not change unintentionally Libraries/Image/ImageTypes.flow.js 1`] = `
44864486
"type ImageComponentStaticsIOS = $ReadOnly<{
4487-
getSize: (
4487+
getSize(uri: string): Promise<{ width: number, height: number }>,
4488+
getSize(
44884489
uri: string,
44894490
success: (width: number, height: number) => void,
44904491
failure?: (error: mixed) => void
4491-
) => void,
4492+
): void,
4493+
getSizeWithHeaders(
4494+
uri: string,
4495+
headers: { [string]: string, ... }
4496+
): Promise<{ width: number, height: number }>,
44924497
getSizeWithHeaders(
44934498
uri: string,
44944499
headers: { [string]: string, ... },

packages/react-native/types/__typetests__/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,12 +1267,18 @@ export class ImageTest extends React.Component {
12671267
}
12681268
});
12691269

1270+
const promise1: Promise<any> = Image.getSize(uri).then(({width, height}) =>
1271+
console.log(width, height),
1272+
);
12701273
Image.getSize(uri, (width, height) => console.log(width, height));
12711274
Image.getSize(
12721275
uri,
12731276
(width, height) => console.log(width, height),
12741277
error => console.error(error),
12751278
);
1279+
const promise2: Promise<any> = Image.getSizeWithHeaders(uri, headers).then(
1280+
({width, height}) => console.log(width, height),
1281+
);
12761282
Image.getSizeWithHeaders(uri, headers, (width, height) =>
12771283
console.log(width, height),
12781284
);

0 commit comments

Comments
 (0)