8
8
* @flow
9
9
*/
10
10
11
- import type { ImageProps } from './types' ;
11
+ import type { ImageProps , Source } from './types' ;
12
12
13
13
import * as React from 'react' ;
14
14
import createElement from '../createElement' ;
@@ -312,9 +312,10 @@ type UseSourceParams = {
312
312
const useSource = (
313
313
{ onLoad, onLoadStart, onLoadEnd, onError } : UseSourceParams ,
314
314
source : ?Source
315
- ) : { state : string , uri : string } = > {
315
+ ) : { state : string , loadedUri : string } = > {
316
+ const lastLoadedSource = React . useRef ( ) ;
316
317
const [ loadedUri , setLoadedUri ] = React . useState ( '' ) ;
317
- const [ state , updateState ] = React . useState ( ( ) => {
318
+ const [ state , setState ] = React . useState ( ( ) => {
318
319
const uri = resolveAssetUri ( source ) ;
319
320
if ( uri != null ) {
320
321
const isLoaded = ImageLoader . has ( uri ) ;
@@ -323,39 +324,50 @@ const useSource = (
323
324
return IDLE ;
324
325
} ) ;
325
326
326
- const loadInput = React . useRef ( null ) ;
327
-
328
- React . useEffect ( ( ) => {
327
+ // This object would only change when load related fields change
328
+ // We try to maintain strict object reference to prevent the effect hook running due to object change
329
+ const stableSource = React . useMemo ( ( ) => {
329
330
const uri = resolveAssetUri ( source ) ;
330
- if ( uri == null ) return ;
331
+ if ( uri == null ) {
332
+ lastLoadedSource . current = null ;
333
+ return null ;
334
+ }
331
335
332
336
let headers ;
333
337
if ( source && typeof source . headers === 'object' ) {
334
338
headers = ( ( source . headers : any ) : { [ key : string ] : string } ) ;
335
339
}
336
340
337
341
const nextInput = { uri , headers } ;
338
- const currentInput = loadInput . current ;
339
- if ( JSON . stringify ( nextInput ) === JSON . stringify ( currentInput ) ) return ;
342
+ if (
343
+ JSON . stringify ( nextInput ) !== JSON . stringify ( lastLoadedSource . current )
344
+ ) {
345
+ lastLoadedSource . current = nextInput ;
346
+ }
347
+
348
+ return lastLoadedSource . current ;
349
+ } , [ source ] ) ;
350
+
351
+ React . useEffect ( ( ) => {
352
+ if ( stableSource == null ) return ;
340
353
341
- updateState ( LOADING ) ;
354
+ setState ( LOADING ) ;
342
355
if ( onLoadStart ) onLoadStart ( ) ;
343
356
344
- loadInput . current = nextInput ;
345
357
const requestId = ImageLoader . load (
346
- nextInput ,
358
+ stableSource ,
347
359
function load ( result ) {
348
- updateState ( LOADED ) ;
360
+ setState ( LOADED ) ;
349
361
setLoadedUri ( result . uri ) ;
350
362
if ( onLoad ) onLoad ( result ) ;
351
363
if ( onLoadEnd ) onLoadEnd ( ) ;
352
364
} ,
353
365
function error ( ) {
354
- updateState ( ERRORED ) ;
366
+ setState ( ERRORED ) ;
355
367
if ( onError ) {
356
368
onError ( {
357
369
nativeEvent : {
358
- error : `Failed to load resource ${ uri } (404)`
370
+ error : `Failed to load resource ${ stableSource . uri } (404)`
359
371
}
360
372
} ) ;
361
373
}
@@ -365,7 +377,7 @@ const useSource = (
365
377
366
378
const effectCleanup = ( ) => ImageLoader . release ( requestId ) ;
367
379
return effectCleanup ;
368
- } , [ updateState , onError , onLoad , onLoadEnd , onLoadStart , source ] ) ;
380
+ } , [ onError , onLoad , onLoadEnd , onLoadStart , stableSource ] ) ;
369
381
370
382
return {
371
383
state,
0 commit comments