Skip to content

Commit fa84da8

Browse files
committed
[change] Image - extract useSource hook
Move the image loading effect here Changed the original logic slightly for less nesting Changed to cover cases where passing the same headers object was starting new loads, as it was treated as a different value due to referential equality
1 parent 427a653 commit fa84da8

File tree

1 file changed

+81
-59
lines changed
  • packages/react-native-web/src/exports/Image

1 file changed

+81
-59
lines changed

packages/react-native-web/src/exports/Image/index.js

Lines changed: 81 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -190,18 +190,10 @@ const Image: React.AbstractComponent<
190190
);
191191
}
192192
}
193-
const [loadedUri, setLoadedUri] = React.useState('');
194-
const [state, updateState] = React.useState(() => {
195-
const uri = resolveAssetUri(source);
196-
if (uri != null) {
197-
const isLoaded = ImageLoader.has(uri);
198-
if (isLoaded) {
199-
return LOADED;
200-
}
201-
}
202-
return IDLE;
203-
});
204-
193+
const { state, loadedUri } = useSource(
194+
{ onLoad, onLoadStart, onLoadEnd, onError },
195+
source
196+
);
205197
const [layout, updateLayout] = React.useState({});
206198
const hasTextAncestor = React.useContext(TextAncestorContext);
207199
const hiddenImageRef = React.useRef(null);
@@ -259,53 +251,6 @@ const Image: React.AbstractComponent<
259251
}
260252
}
261253

262-
// Image loading
263-
const uri = resolveAssetUri(source);
264-
let headers;
265-
if (source && typeof source.headers === 'object') {
266-
headers = ((source.headers: any): { [key: string]: string });
267-
}
268-
269-
React.useEffect(() => {
270-
if (uri != null) {
271-
updateState(LOADING);
272-
if (onLoadStart) onLoadStart();
273-
274-
const requestId = ImageLoader.load(
275-
{ uri, headers },
276-
function load(result) {
277-
updateState(LOADED);
278-
setLoadedUri(result.uri);
279-
if (onLoad) {
280-
onLoad(result);
281-
}
282-
if (onLoadEnd) {
283-
onLoadEnd();
284-
}
285-
},
286-
function error() {
287-
updateState(ERRORED);
288-
if (onError) {
289-
onError({
290-
nativeEvent: {
291-
error: `Failed to load resource ${uri} (404)`
292-
}
293-
});
294-
}
295-
if (onLoadEnd) {
296-
onLoadEnd();
297-
}
298-
}
299-
);
300-
301-
const effectCleanup = () => {
302-
if (requestId) ImageLoader.release(requestId);
303-
};
304-
305-
return effectCleanup;
306-
}
307-
}, [updateState, onError, onLoad, onLoadEnd, onLoadStart, uri, headers]);
308-
309254
return (
310255
<View
311256
{...rest}
@@ -356,6 +301,83 @@ ImageWithStatics.queryCache = function (uris) {
356301
return ImageLoader.queryCache(uris);
357302
};
358303

304+
type UseSourceParams = {
305+
onLoad?: Function,
306+
onLoadStart?: Function,
307+
onLoadEnd?: Function,
308+
onError?: Function
309+
};
310+
311+
/**
312+
* Image loading/state management hook
313+
* @param params
314+
* @param source
315+
* @returns {{state: string, uri: string}}
316+
*/
317+
const useSource = (
318+
{ onLoad, onLoadStart, onLoadEnd, onError }: UseSourceParams,
319+
source: ?Source
320+
): { state: string, uri: string } => {
321+
const [loadedUri, setLoadedUri] = React.useState('');
322+
const [state, updateState] = React.useState(() => {
323+
const uri = resolveAssetUri(source);
324+
if (uri != null) {
325+
const isLoaded = ImageLoader.has(uri);
326+
if (isLoaded) return LOADED;
327+
}
328+
return IDLE;
329+
});
330+
331+
const loadInput = React.useRef(null);
332+
333+
React.useEffect(() => {
334+
const uri = resolveAssetUri(source);
335+
if (uri == null) return;
336+
337+
let headers;
338+
if (source && typeof source.headers === 'object') {
339+
headers = ((source.headers: any): { [key: string]: string });
340+
}
341+
342+
const nextInput = { uri, headers };
343+
const currentInput = loadInput.current;
344+
if (JSON.stringify(nextInput) === JSON.stringify(currentInput)) return;
345+
346+
updateState(LOADING);
347+
if (onLoadStart) onLoadStart();
348+
349+
loadInput.current = nextInput;
350+
const requestId = ImageLoader.load(
351+
nextInput,
352+
function load(result) {
353+
updateState(LOADED);
354+
setLoadedUri(result.uri);
355+
if (onLoad) onLoad(result);
356+
if (onLoadEnd) onLoadEnd();
357+
},
358+
function error() {
359+
updateState(ERRORED);
360+
if (onError) {
361+
onError({
362+
nativeEvent: {
363+
error: `Failed to load resource ${uri} (404)`
364+
}
365+
});
366+
}
367+
if (onLoadEnd) onLoadEnd();
368+
}
369+
);
370+
371+
const effectCleanup = () => ImageLoader.release(requestId);
372+
return effectCleanup;
373+
}, [updateState, onError, onLoad, onLoadEnd, onLoadStart, source]);
374+
375+
return {
376+
state,
377+
loadedUri
378+
};
379+
};
380+
359381
const styles = StyleSheet.create({
360382
root: {
361383
flexBasis: 'auto',

0 commit comments

Comments
 (0)