View commands (old arch)
info
You may notice, that JS specs contain codegen-related methods, classes, types, etc. to make things more future-proof.
That's because:
- those elements are available since RN older versions (even from v0.65)
- those elements are falling back to "old architecture" implementation (e.g. codegenNativeComponent)
- it introduces type safety for exposed native parts on JS side
- it's much easier to keep single specification on JS side - when old arch will be dropped, there'll be no need to change anything on JS side
So to make it easier, let's use them, to get you more familiar with it 👍
Commands declaration
To add commands to native component, JS spec needs to commands object made with codegenNativeCommands
method:
src/MyAwesomeViewNativeComponent.ts
import * as React from 'react';
import type { HostComponent, ViewProps } from 'react-native';
import type { Double } from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export interface MyAwesomeViewProps extends ViewProps {}
export interface MyAwesomeViewNativeCommands {
doAwesomeJob: (viewRef: React.ElementRef<<HostComponent<MyAwesomeViewProps>>>, arg: Double) => void
}
// codegenNativeCommands uses UIManager.dispatchViewManagerCommand on old arch
export const MyAwesomeViewCommands = codegenNativeCommands<MyAwesomeViewNativeCommands>({
supportedCommands: [ 'doAwesomeJob' ],
});
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
Commands implementation in native code
- iOS
- Android
ios/MyAwesomeViewManager.mm
#import <React/RCTUIManager.h>
// ...
RCT_EXPORT_METHOD(doAwesomeJob:(nonnull NSNumber*) reactTag, arg:(double) arg) {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
MyAwesomeView *view = viewRegistry[reactTag];
if (!view || ![view isKindOfClass:[MyAwesomeView class]]) {
return;
}
// ...
}];
}
To implement commands for iOS native component, view manager class has to declare method with RCT_EXPORT_METHOD
macro,
where view that should handle the command is retrieved with UIManager's - addUIBlock:
method.
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ViewGroupManager
// ...
@ReactModule(name = MyAwesomeView.NAME)
class MyAwesomeViewManager : ViewGroupManager<MyAwesomeView>() {
override fun receiveCommand(root: MyAwesomeView, commandId: String?, args: ReadableArray?) {
super.receiveCommand(root, commandId, args)
when (commandId) {
"doAwesomeJob" -> {
val value = args!!.getDouble(0)
doAwesomeJob(root, value)
}
}
}
private fun doAwesomeJob(view: MyAwesomeView, arg: Double) {
// ...
}
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ViewGroupManager;
// ...
@ReactModule(name = MyAwesomeView.NAME)
public class MyAwesomeViewManager extends ViewGroupManager<MyAwesomeView> {
@Override
public void receiveCommand(MyAwesomeView root, String commandId, @Nullable ReadableArray args) {
super.receiveCommand(root, commandId, args);
switch (commandId) {
case "doAwesomeJob":
final double value = args.getDouble(0);
doAwesomeJob(root, value);
break;
}
}
private void doAwesomeJob(MyAwesomeView view, double arg) {
// ...
}
// ...
}
To implement command for Android native component, it has to implement receiveCommand
method in view manager class, where command and args are parsed and forwarded to specific method.