Skip to content

Image: changing load callback identity aborts and restarts the image load #2850

Description

@AbdullahAnsarii

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

The image-loading effect in Image lists onError, onLoad, onLoadEnd, and onLoadStart in its dependency array (source). Passing inline handlers — new function identities on every parent render — re-runs the effect for an unchanged uri: the cleanup aborts the in-flight request, state resets to LOADING, onLoadStart fires again, and the load restarts. If a handler sets state (e.g. onLoadEnd={() => setLoading(false)}), the re-render produces fresh identities and the cycle loops indefinitely — the image never settles even though the browser has it fully decoded. React Native is unaffected by handler identity, so code that works on iOS/Android breaks on web.

Test case: https://codesandbox.io/p/sandbox/rnw-image-callback-identity-repro-forked-y6mngh — watch the onLoadStart/onLoadEnd call counters climb indefinitely while "Loading..." never settles, and the network panel restart the same request.

Hit in production in rn-story: the story viewer's loader flickered forever on web while working fine on iOS/Android. Worked around in v2.0.1 by memoizing every handler with useCallback.

Related history: the source-object version of this problem was addressed by having the effect depend on the resolved uri string rather than the object — the callbacks still retrigger it. I have a fix with regression tests ready and will open a PR.

Expected behavior

One load per uri. onLoadStart, onLoad, and onLoadEnd fire once per actual load, regardless of how often the parent re-renders or whether the handlers are inline functions. Changing a handler's identity should never abort an in-flight request, reset state to LOADING, or re-fire onLoadStart — when the load settles, the most recent handlers should be invoked. This matches React Native, where handler identity has no effect on loading.

Steps to reproduce

  1. Render an <Image source={{ uri }}> with inline onLoadStart={() => setLoading(true)} and onLoadEnd={() => setLoading(false)}.
  2. The load completing sets state → re-render → new handler identities → the load effect re-runs, aborts, and restarts the load for the same uri.
  3. Observe the loop in https://codesandbox.io/p/sandbox/rnw-image-callback-identity-repro-forked-y6mngh (call counters + network panel).

Test case

https://codesandbox.io/p/sandbox/rnw-image-callback-identity-repro-forked-y6mngh

Additional comments

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions