React Native自定義組件與輸出方法詳解
簡介
如果你看的這一篇,需要你對ReactNative的開發(fā)有一定的了解,此文講的是在ReactNative提供的組件不能滿足需求,或者native用于較成熟的組件想要輸出,那么就需要用到自定義組件了.
通過該文,我們也可以對native和JS交互方式進行初步了解,關于輸出方法內(nèi)部實現(xiàn),我們下一篇再剖.
Native module
native module就是實現(xiàn)了RCTBridgeModule協(xié)議的OC類.RCT就是ReaCT的縮寫.
具體步驟如下
- 引入
#import <React/RCTBridgeModule.h>
類,然后遵守RCTBridgeModule協(xié)議. - 實現(xiàn)
RCT_EXPORT_MODULE(customName)
方法. customName是自定義的組件名,如果不填默認為當前類名.這個組件名是用于向JS輸出.
輸出組建后,默認不會向JS輸出任何方法,想要輸出方法,需要自定義實現(xiàn)方法輸出,使用宏RCT_EXPORT_METHOD ()
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location) { RCTLogInfo(@"Pretending to create an event %@ at %@", name, location); }
對于JS端,調(diào)用時就可以如下
import {NativeModules} from 'react-native'; var CustomName = NativeModules.CalendarManager; CustomName.addEvent('Birthday Party', '4 Privet Drive, Surrey');
注意
向JS輸出的方法名,是RCT_EXPORT_METHOD之后,第一個冒號之前的名字.如果native已經(jīng)暴露了多個冒號之前同名的方法,RN提供了RCT_REMAP_METHOD ()來制定方法名.
另外一點, RCT_EXPORT_METHOD回調(diào)進入的方法,默認并不在主線程,如果想要進行主線程的方法調(diào)用,需要手動進行dispatch_async(dispatch_get_main_queue(), ^{});回到主線程
RCT_EXPORT_METHOD參數(shù)
RCT_EXPORT_METHOD支持如下的參數(shù)類型
- string (NSString)
- number (NSInteger, float, double, CGFloat, NSNumber)
- boolean (BOOL, NSNumber)
- array (NSArray) of any types from this list
- object (NSDictionary) with string keys and values of any type from this list
- function (RCTResponseSenderBlock)
也支持所有RCTConvert支持的類型.
回調(diào)
native module支持回調(diào)類型RCTResponseSenderBlock
RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) { NSArray *events = ... callback(@[[NSNull null], events]); }
RCTResponseSenderBlock只支持一個參數(shù):一個包含了多個參數(shù)的數(shù)組.在JS端可以如下,默認第一個參數(shù)是error.當沒有錯誤時error為空.
CalendarManager.findEvents((error, events) => { if (error) { console.error(error); } else { this.setState({events: events}); } });
native module只能調(diào)用一次回調(diào).如果想傳遞錯誤,通過RCTUtils.h類中的RCTMakeError來創(chuàng)建.
Promise
Promise是用于實現(xiàn)異步操作async/await的工具類.如果最后一個參數(shù)類型為RCTPromiseResolveBlock和RCTPromiseRejectBlock,JS端會返回一個promise對象,進行一步操作.
RCT_REMAP_METHOD(findEvents, findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSArray *events = ... if (events) { resolve(events); } else { NSError *error = ... reject(@"no_events", @"There were no events", error); } }
JS端因為獲取的是promise對象,可以使用await關鍵字進行異步調(diào)用并等待結果
async function updateEvents() { try { var events = await CalendarManager.findEvents(); this.setState({events}); } catch (e) { console.error(e); } } updateEvents();
關于線程
JS執(zhí)行native module是在一個單獨的線程實現(xiàn)的,可以通過- (dispatch_queue_t)methodQueue
來控制.如果返回主線程,所有執(zhí)行的方法會在主線程被執(zhí)行.
- (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); }
方法methodQueue之后在組件初始化時被調(diào)用一次.
輸出實例
除了可以輸出方法,還有輸出實例.
- (NSDictionary *)constantsToExport { return @{ @"firstDayOfTheWeek": @"Monday" }; }
在JS端可以直接獲取console.log(CalendarManager.firstDayOfTheWeek);
只有在初始化時實例輸出才是有效的,如果在運行時修改constantsToExport是不會影響JS環(huán)境的數(shù)據(jù)的.
輸出枚舉
通過typedef NS_ENUM()定義的枚舉,可以通過增加RCTConvert的擴展來完成
@implementation RCTConvert (StatusBarAnimation) RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone), @"statusBarAnimationFade" : @(UIStatusBarAnimationFade), @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)}), UIStatusBarAnimationNone, integerValue) @end
之后就可以通過輸出屬性和方法等方式在JS中使用了.
native向JS發(fā)方法
想給JS發(fā)方法,可以繼承類RCTEventEmitter,實現(xiàn)supportedEvents方法,然后通過調(diào)用self sendEventWithName:即可.
RCT_EXPORT_MODULE(); - (NSArray<NSString *> *)supportedEvents { return @[@"EventReminder"]; } - (void)calendarEventReminderReceived:(NSNotification *)notification { NSString *eventName = notification.userInfo[@"name"]; [self sendEventWithName:@"EventReminder" body:@{@"name": eventName}]; }
JS端可以通過NativeEventEmitter進行注冊和調(diào)用
import { NativeEventEmitter, NativeModules } from 'react-native'; const { CalendarManager } = NativeModules; const calendarManagerEmitter = new NativeEventEmitter(CalendarManager); const subscription = calendarManagerEmitter.addListener( 'EventReminder', (reminder) => console.log(reminder.name) ); ... // Don't forget to unsubscribe, typically in componentWillUnmount subscription.remove();
注意取消訂閱,一般在componentWillUnmount內(nèi)執(zhí)行.
客戶端可以通過一些方式獲取JS注冊和移除訂閱的事件,來優(yōu)化只在有訂閱者的情況下才發(fā)送事件.
// Will be called when this module's first listener is added. -(void)startObserving { hasListeners = YES; // Set up any upstream listeners or background tasks as necessary } // Will be called when this module's last listener is removed, or on dealloc. -(void)stopObserving { hasListeners = NO; // Remove upstream listeners, stop unnecessary background tasks }
資料
總結
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
使用React hook實現(xiàn)remember me功能
相信大家在使用 React 寫頁面的時候都遇到過完成 Remember me 的需求吧!本文就將這個需求封裝在一個 React hook 中以供后續(xù)的使用,覺得有用的同學可以收藏起來以備不時之需,感興趣的小伙伴跟著小編一起來看看吧2024-04-04React Native實現(xiàn)進度條彈框的示例代碼
本篇文章主要介紹了React Native實現(xiàn)進度條彈框的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07react?+?vite?+?ts項目中優(yōu)雅使用.svg文件
這篇文章主要為大家介紹了react?+?vite?+?ts項目中優(yōu)雅使用.svg文件,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08用react-redux實現(xiàn)react組件之間數(shù)據(jù)共享的方法
這篇文章主要介紹了用react-redux實現(xiàn)react組件之間數(shù)據(jù)共享的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06