View props (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 👍
Boolean prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
enabled: boolean
checked?: boolean
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(checked, NSNumber)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "enabled")
fun setEnabled(view: MyAwesomeView, enabled: Boolean) {
// ...
}
@ReactProp(name = "checked")
fun setChecked(view: MyAwesomeView, checked: Boolean?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "enabled")
public void setEnabled(MyAwesomeView view, boolean enabled) {
// ...
}
@ReactProp(name = "checked")
public void setChecked(MyAwesomeView view, @Nullable Boolean checked) {
// ...
}
Number prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import type {
Double,
Float,
Int32,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
precision: Double
optionalPrecision?: Double
price: Float
discount?: Float
count: Int32
optionalCount?: Int32
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(precision, double)
RCT_EXPORT_VIEW_PROPERTY(optionalPrecision, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(price, float)
RCT_EXPORT_VIEW_PROPERTY(discount, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(count, int)
RCT_EXPORT_VIEW_PROPERTY(optionalCount, NSNumber)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "precision")
fun setPrecision(view: MyAwesomeView, precision: Double) {
// ...
}
@ReactProp(name = "optionalPrecision")
fun setOptionalPrecision(view: MyAwesomeView, optionalPrecision: Double?) {
// ...
}
@ReactProp(name = "price")
fun setPrice(view: MyAwesomeView, price: Float) {
// ...
}
@ReactProp(name = "discount")
fun setDiscount(view: MyAwesomeView, discount: Float?) {
// ...
}
@ReactProp(name = "count")
fun setCount(view: MyAwesomeView, count: Int) {
// ...
}
@ReactProp(name = "optionalCount")
fun setOptionalCount(view: MyAwesomeView, optionalCount: Int?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "precision")
public void setPrecision(MyAwesomeView view, double precision) {
// ...
}
@ReactProp(name = "optionalPrecision")
public void setOptionalPrecision(MyAwesomeView view, @Nullable Double optionalPrecision) {
// ...
}
@ReactProp(name = "price")
public void setPrice(MyAwesomeView view, float price) {
// ...
}
@ReactProp(name = "discount")
public void setDiscount(MyAwesomeView view, @Nullable Float discount) {
// ...
}
@ReactProp(name = "count")
public void setCount(MyAwesomeView view, int count) {
// ...
}
@ReactProp(name = "optionalCount")
public void setOptionalCount(MyAwesomeView view, @Nullable Integer optionalCount) {
// ...
}
String prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
name: string
label?: string
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(name, NSString)
RCT_EXPORT_VIEW_PROPERTY(label, NSString)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "name")
fun setName(view: MyAwesomeView, name: String) {
// ...
}
@ReactProp(name = "label")
fun setLabel(view: MyAwesomeView, label: String?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "name")
public void setName(MyAwesomeView view, String name) {
// ...
}
@ReactProp(name = "label")
public void setLabel(MyAwesomeView view, @Nullable String label) {
// ...
}
Array prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
data: ReadonlyArray<number>
optionalData?: ReadonlyArray<Readonly<{ title: string, description: string }>>
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(data, NSArray)
RCT_EXPORT_VIEW_PROPERTY(optionalData, NSArray)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "data")
fun setData(view: MyAwesomeView, data: ReadableArray) {
// ...
}
@ReactProp(name = "optionalData")
fun setOptionalData(view: MyAwesomeView, optionalData: ReadableArray?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "data")
public void setData(MyAwesomeView view, ReadableArray data) {
// ...
}
@ReactProp(name = "optionalData")
public void setOptionalData(MyAwesomeView view, @Nullable ReadableArray optionalData) {
// ...
}
Object prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
config: Readonly<{ flag: boolean, option: string }>
optionalConfig?: Readonly<{ count: number }>
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(config, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(optionalConfig, NSDictionary)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "config")
fun setConfig(view: MyAwesomeView, config: ReadableMap) {
// ...
}
@ReactProp(name = "optionalConfig")
fun setOptionalConfig(view: MyAwesomeView, optionalConfig: ReadableMap?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "config")
public void setConfig(MyAwesomeView view, ReadableMap config) {
// ...
}
@ReactProp(name = "optionalConfig")
public void setOptionalConfig(MyAwesomeView view, @Nullable ReadableMap optionalConfig) {
// ...
}
Color prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { ColorValue, HostComponent, ViewProps } from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
tintColor: ColorValue
optionalColor?: ColorValue
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(optionalColor, UIColor)
- Kotlin
- Java
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.uimanager.annotations.ReactProp
// ...
@ReactProp(name = "tintColor")
fun setTintColor(view: MyAwesomeView, tintColor: Int?) {
// ...
}
@ReactProp(name = "optionalColor")
fun setOptionalColor(view: MyAwesomeView, optionalColor: Int?) {
// ...
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.annotations.ReactProp;
// ...
@ReactProp(name = "tintColor")
public void setTintColor(MyAwesomeView view, @Nullable Integer tintColor) {
// ...
}
@ReactProp(name = "optionalColor")
public void setOptionalColor(MyAwesomeView view, @Nullable Integer optionalColor) {
// ...
}
Event handler prop
- JS Spec
- iOS Spec
- Android Spec
src/MyAwesomeViewNativeComponent.ts
import type { HostComponent, ViewProps } from 'react-native';
import type {
BubblingEventHandler,
DirectEventHandler,
} from 'react-native/Libraries/Types/CodegenTypes';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
// ...
export interface MyAwesomeViewProps extends ViewProps {
onAwesomeBubblingEvent?: BubblingEventHandler<Readonly<{ arg: string }>>
onAwesomeDirectEvent?: DirectEventHandler<Readonly<{ arg: string }>>
}
// codegenNativeComponent uses requireNativeComponent on old arch
export default codegenNativeComponent<MyAwesomeViewProps>('MyAwesomeView') as HostComponent<MyAwesomeViewProps>;
ios/MyAwesomeViewManager.mm
RCT_EXPORT_VIEW_PROPERTY(onAwesomeBubblingEvent, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onAwesomeDirectEvent, RCTDirectEventBlock)
- Kotlin
- Java
android/src/main/java/com/myawesomeapp/OnAwesomeBubblingEvent.kt
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.Event
// ...
class OnAwesomeBubblingEvent(
surfaceId: Int,
viewId: Int,
private val payload: String
) : Event<OnAwesomeBubblingEvent>(surfaceId, viewId) {
override fun getEventName() = NAME
override fun getEventData(): WritableMap? {
return createPayload()
}
private fun createPayload() = Arguments.createMap().apply {
putString("arg", payload)
}
companion object {
const val NAME = "topAwesomeBubblingEvent"
const val EVENT_PROP_NAME = "onAwesomeBubblingEvent"
}
}
android/src/main/java/com/myawesomeapp/OnAwesomeDirectEvent.kt
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.events.Event
// ...
class OnAwesomeDirectEvent(
surfaceId: Int,
viewId: Int,
private val payload: String
) : Event<OnAwesomeDirectEvent>(surfaceId, viewId) {
override fun getEventName() = NAME
override fun getEventData(): WritableMap? {
return createPayload()
}
private fun createPayload() = Arguments.createMap().apply {
putString("arg", payload)
}
companion object {
const val NAME = "topAwesomeDirectEvent"
const val EVENT_PROP_NAME = "onAwesomeDirectEvent"
}
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.kt
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
// ...
override fun addEventEmitters(reactContext: ThemedReactContext, view: MyAwesomeView) {
super.addEventEmitters(reactContext, view)
view.setOnAwesomeViewListener(object : MyAwesomeView.OnAwesomeViewListener {
override fun onAwesomeBubblingEvent(payload: String) {
UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
?.dispatchEvent(
OnAwesomeBubblingEvent(
UIManagerHelper.getSurfaceId(reactContext),
view.id,
payload
)
)
}
override fun onAwesomeDirectEvent(payload: String) {
UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
?.dispatchEvent(
OnAwesomeDirectEvent(
UIManagerHelper.getSurfaceId(reactContext),
view.id,
payload
)
)
}
})
}
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
return MapBuilder.of(
OnAwesomeBubblingEvent.NAME,
MapBuilder.of("registrationName", OnAwesomeBubblingEvent.EVENT_PROP_NAME)
)
}
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
return MapBuilder.of(
OnAwesomeDirectEvent.NAME,
MapBuilder.of("registrationName", OnAwesomeDirectEvent.EVENT_PROP_NAME)
)
}
android/src/main/java/com/myawesomeapp/OnAwesomeBubblingEvent.java
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
// ...
public class OnAwesomeBubblingEvent extends Event<OnAwesomeBubblingEvent> {
private final String payload;
public static final String NAME = "topAwesomeBubblingEvent";
public static final String EVENT_PROP_NAME = "onAwesomeBubblingEvent";
public OnAwesomeBubblingEvent(int surfaceId, int viewId, String payload) {
super(surfaceId, viewId);
this.payload = payload;
}
@Override
public String getEventName() {
return NAME;
}
@Override
@Nullable
public WritableMap getEventData() {
return createPayload();
}
private WritableMap createPayload() {
WritableMap eventPayload = Arguments.createMap();
eventPayload.putString("arg", payload);
return eventPayload;
}
}
android/src/main/java/com/myawesomeapp/OnAwesomeDirectEvent.java
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
// ...
public class OnAwesomeDirectEvent extends Event<OnAwesomeDirectEvent> {
private final String payload;
public static final String NAME = "topAwesomeDirectEvent";
public static final String EVENT_PROP_NAME = "onAwesomeDirectEvent";
public OnAwesomeDirectEvent(int surfaceId, int viewId, String payload) {
super(surfaceId, viewId);
this.payload = payload;
}
@Override
public String getEventName() {
return NAME;
}
@Override
@Nullable
public WritableMap getEventData() {
return createPayload();
}
private WritableMap createPayload() {
WritableMap eventPayload = Arguments.createMap();
eventPayload.putString("arg", payload);
return eventPayload;
}
}
android/src/main/newarch/com/myawesomeapp/MyAwesomeViewManager.java
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.events.EventDispatcher;
import java.util.Map;
// ...
@Override
protected void addEventEmitters(ThemedReactContext reactContext, MyAwesomeView view) {
super.addEventEmitters(reactContext, view);
view.setOnAwesomeViewListener(new MyAwesomeView.OnAwesomeViewListener() {
@Override
public void onAwesomeBubblingEvent(String payload) {
final EventDispatcher dispatcher =
UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.getId());
if (dispatcher != null) {
dispatcher.dispatchEvent(
new OnAwesomeBubblingEvent(
UIManagerHelper.getSurfaceId(reactContext),
view.getId(),
payload
)
);
}
}
@Override
public void onAwesomeDirectEvent(String payload) {
final EventDispatcher dispatcher =
UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.getId());
if (dispatcher != null) {
dispatcher.dispatchEvent(
new OnAwesomeDirectEvent(
UIManagerHelper.getSurfaceId(reactContext),
view.getId(),
payload
)
);
}
}
});
}
@Override
public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
return MapBuilder.of(
OnAwesomeBubblingEvent.NAME,
MapBuilder.of("registrationName", OnAwesomeBubblingEvent.EVENT_PROP_NAME)
)
}
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
OnAwesomeDirectEvent.NAME,
MapBuilder.of("registrationName", OnAwesomeDirectEvent.EVENT_PROP_NAME)
)
}