It's not possible to pass ArrayBuffer to Nitro View as prop
What's happening?
I want to create Nitro View with prop that accepts ArrayBuffer, but it will throw error in Swift component (did not tested Kotlin).
Reproduceable Code
export interface QRCodeViewProps extends HybridViewProps {
data: ArrayBuffer;
}
// later
const data = new ArrayBuffer(42);
<QRCode data={data} />
Swift component
var data: ArrayBufferHolder = ArrayBufferHolder.allocate(size: 1) {
didSet {
let data = qrCodeData.toData(copyIfNeeded: true)
// ....
}
}
Relevant log output
-
Device
iPhone Pro 16 (emulator)
Nitro Modules Version
0.24.1
Nitrogen Version
0.24.1
Can you reproduce this issue in the Nitro Example app here?
I didn't try (⚠️ your issue might get ignored & closed if you don't try this)
Additional information
- [ ] I am using Expo
- [x] I am using Nitrogen (nitro-codegen)
- [x] I have read and followed the Troubleshooting Guide.
- [x] I created a reproduction PR to reproduce this issue here in the nitro repo. (See Contributing for more information)
- [x] I searched for similar issues in this repository and found none.
Valid 👍
Worth noting that a fair workaround would be to directly set the prop on the hybridRef (which avoids any React magic and just operates directly on the HybridObject):
export interface QRCodeViewProps extends HybridViewProps {
data: ArrayBuffer
}
// later
const data = new ArrayBuffer(42);
<QRCode hybridRef={{ f: (ref) => { ref.data = data } }} />
@mrousavy Thanks for workaround.
Can maybe explain little bit more why this doesn't produce thread hop? My understanding is Swift view code is running on different thread so it's ref methods should too.
This is the only case where an implicit Thread hop occurs in Nitro. By default, everything is sync - except for HybridView prop setters.
Those go through React Native's view diffing mechanism, and this just schedules all prop changes on the UI Thread. That's why this happens.
React Native schedules this function on the UI Thread: https://github.com/mrousavy/nitro/blob/60bedc58bf816c56b446d7871f41236c2ab25b4c/packages/react-native-nitro-image/nitrogen/generated/ios/c%2B%2B/views/HybridTestViewComponent.mm#L64-L99
My understanding is Swift view code is running on different thread so it's ref methods should too.
Threading is only implicit because of React Native. Nitro itself does not do any thread hops for you. You are responsible for doing that. it's sync by default.
So that's why the hybridRef way works - it gives you a direct reference to the HybridObject. Anything you do on it, even setting props, will be fully sync - no thread hops involved.
Now that I think of it, you can even use this with your current approach;
export interface QRCodeViewProps extends HybridViewProps {
data: ArrayBuffer
}
// later
const data = new ArrayBuffer(42);
<QRCode hybridRef={{ f: (ref) => { ref.data = data } }} />
No need for a method even.
It's just if you set a prop through React/JSX, React Native's implementation will do a Thread hop from JS to UI. That's just how it works.
So do I understand correctly that if I use ref approach it will run that Swift component update on JS thread instead of UI thread?
Yep 👍
Thanks again for explanation, I didn't even know it's possible to run native components on JS thread.
#736 solves this - if you create your ArrayBuffer on the native side, it's owning - and going through JS to native again won't lose that information from now on!