Skip to content

Commit 9e05b48

Browse files
committed
fix(web): keep function identiy accross renders
1 parent 5f9c32e commit 9e05b48

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import StyleSheet from '../StyleSheet';
2020
import TextAncestorContext from '../Text/TextAncestorContext';
2121
import View from '../View';
2222
import { warnOnce } from '../../modules/warnOnce';
23+
import useCallbackRef from '../../vendor/react-native/Utilities/useCallbackRef';
2324

2425
export type { ImageProps };
2526

@@ -230,6 +231,12 @@ const Image: React.AbstractComponent<
230231
const backgroundImage = displayImageUri ? `url("${displayImageUri}")` : null;
231232
const backgroundSize = getBackgroundSize();
232233

234+
const onErrorRef = useCallbackRef(onError);
235+
const onLoadRef = useCallbackRef(onLoad);
236+
const onLoadEndRef = useCallbackRef(onLoadEnd);
237+
const onLoadStartRef = useCallbackRef(onLoadStart);
238+
239+
233240
// Accessibility image allows users to trigger the browser's image context menu
234241
const hiddenImage = displayImageUri
235242
? createElement('img', {
@@ -276,32 +283,32 @@ const Image: React.AbstractComponent<
276283

277284
if (uri != null) {
278285
updateState(LOADING);
279-
if (onLoadStart) {
280-
onLoadStart();
286+
if (onLoadStartRef.current) {
287+
onLoadStartRef.current();
281288
}
282289

283290
requestRef.current = ImageLoader.load(
284291
uri,
285292
function load(e) {
286293
updateState(LOADED);
287-
if (onLoad) {
288-
onLoad(e);
294+
if (onLoadRef.current) {
295+
onLoadRef.current(e);
289296
}
290-
if (onLoadEnd) {
291-
onLoadEnd();
297+
if (onLoadEndRef.current) {
298+
onLoadEndRef.current();
292299
}
293300
},
294301
function error() {
295302
updateState(ERRORED);
296-
if (onError) {
297-
onError({
303+
if (onErrorRef.current) {
304+
onErrorRef.current({
298305
nativeEvent: {
299306
error: `Failed to load resource ${uri} (404)`
300307
}
301308
});
302309
}
303-
if (onLoadEnd) {
304-
onLoadEnd();
310+
if (onLoadEndRef.current) {
311+
onLoadEndRef.current();
305312
}
306313
}
307314
);
@@ -315,7 +322,7 @@ const Image: React.AbstractComponent<
315322
}
316323

317324
return abortPendingRequest;
318-
}, [uri, requestRef, updateState, onError, onLoad, onLoadEnd, onLoadStart]);
325+
}, [uri, requestRef, updateState, onErrorRef, onLoadRef, onLoadEndRef, onLoadStartRef]);
319326

320327
return (
321328
<View
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Helper to keep the same ref of a function accross renders
3+
*
4+
*/
5+
import { useLayoutEffect, useEffect, useRef } from 'react';
6+
7+
export default function useCallbackRef(callback) {
8+
const callbackRef = useRef(callback);
9+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
10+
11+
useIsomorphicLayoutEffect(() => {
12+
callbackRef.current = callback;
13+
}, [callback]);
14+
15+
return callbackRef;
16+
}

0 commit comments

Comments
 (0)