mrousavy / mrousavy/react-native-nitro-image
<NitroImage /> emits no load or error events, so expo-image's transition cannot be reproduced
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 652
- Forks
- 37
- Avg merge
- 56m
- Merged PRs (30d)
- 6
Description
Version
react-native-nitro-image@0.15.2.
The gap
<NitroImage /> emits no events at all. The generated view config is the whole surface:
nitrogen/generated/shared/json/NitroImageViewConfig.json
{
"uiViewClassName": "NitroImageView",
"supportsRawText": false,
"bubblingEventTypes": {},
"directEventTypes": {},
"validAttributes": {
"image": true,
"resizeMode": true,
"recyclingKey": true,
"hybridRef": true
}
}
Four props, zero events, and NativeNitroImageViewMethods extends HybridViewMethods {} is empty
too. So there is no onLoad, no onError, no onDisplay.
Why it matters beyond "a missing callback"
The concrete thing it blocks is a cross-fade. expo-image has transition={220}, a
cross-dissolve when the source changes, and react-native-fast-image and react-native's own
Image both at least give you onLoad so you can build one. With <NitroImage /> there is no
transition prop and no event to drive one yourself, so a source change is always a hard cut.
That is most visible in exactly the case this library is good at. If you are swapping the source
on a view that is already showing something - a progressively refined image, a low-res preview
replaced by the full one, a thumbnail replaced by the original - the swap is the moment the user
sees, and right now it can only pop.
useImage() is not a substitute. It tells you when a frame is ready, but using it means holding
the decoded Image in JS and passing image={image}, and the spec is explicit that this opts
out of the recycling path:
Image: Shows a specific in-memoryImageinstance. Even when the view goes invisible, the
image will still be in-memory.
So the only way to observe a load today is to give up the memory behaviour that made you reach
for the ImageLoader variant in the first place. (See also #124, which is about the retention
side of that same trade.)
Secondary losses from having no events: no way to know a load failed so you can show your own
fallback, no way to measure time-to-first-paint per image, and no way to tell "still loading"
apart from "loaded, but the image is genuinely blank".
Suggested fix
Direct events on the view, matching what the ecosystem already expects:
export interface NativeNitroImageViewProps extends HybridViewProps {
// ...existing
onLoad?: (image: { width: number; height: number }) => void
onError?: (error: { message: string }) => void
}
onLoad fired after the bitmap is actually set on the native view (not when the promise
resolves, so it lines up with the frame the user sees) would be enough to build a fade in
Reanimated. onError fired from the catch that HybridImageView.onAppear already swallows
into a Log.e on Android would be a straight improvement over the current behaviour, which is
that a failed load is silent to the app.
A native transition prop would be nicer still for the common case, since the crossfade then
never crosses the bridge, but onLoad is the thing that unblocks people.
Context
Found while migrating Foodr off expo-image onto this
library (mrousavy/Foodr#19). The app streams generated dish photos - a preview frame lands in a
fraction of a second and is replaced by the finished image a few seconds later - and today
transition={220} is what makes that read as the picture sharpening rather than as the card
flickering. The migration PR is open and ships without the cross-fade, with a TODO at the call
site pointing here.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with nitrogen/generated/shared/json/NitroImageViewConfig.json and the NativeNitroImageViewProps interface, then inspect HybridImageView.onAppear and its swallowed error path. Trace how the native view reports state across platforms. Done means direct onLoad and onError events are exposed and fire when the bitmap is set or loading fails, without requiring the in-memory Image path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react-native, typescript
- Domain
- mobile
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100