diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md index c7dcf2eb9..dbbcd0cd3 100644 --- a/docs/NativeModulesAndroid.md +++ b/docs/NativeModulesAndroid.md @@ -124,7 +124,7 @@ mReactInstanceManager = ReactInstanceManager.builder() To make it simpler to access your new functionality from JavaScript, it is common to wrap the native module in a JavaScript module. This is not necessary but saves the consumers of your library the need to pull it off of `NativeModules` each time. This JavaScript file also becomes a good location for you to add any JavaScript side functionality. -```java +```js /** * @providesModule ToastAndroid */ @@ -203,6 +203,62 @@ A native module is supposed to invoke its callback only once. It can, however, s It is very important to highlight that the callback is not invoked immediately after the native function completes - remember that bridge communication is asynchronous, and this too is tied to the run loop. +### Promises + +Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameter of a bridged native method is a `Promise`, its corresponding JS method will return a JS Promise object. + +Refactoring the above code to use a promise instead of callbacks looks like this: + +```java +public class UIManagerModule extends ReactContextBaseJavaModule { + +... + + @ReactMethod + public void measureLayout( + int tag, + int ancestorTag, + Promise promise) { + try { + measureLayout(tag, ancestorTag, mMeasureBuffer); + + WritableMap map = Arguments.createMap(); + + map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0])); + map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1])); + map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2])); + map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3])); + + promise.resolve(map); + } catch (IllegalViewOperationException e) { + promise.reject(e.getMessage()); + } + } + +... +``` + +The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result: + +```js +async function measureLayout() { + try { + var { + relativeX, + relativeY, + width, + height, + } = await UIManager.measureLayout(100, 100); + + console.log(relativeX + ':' + relativeY + ':' + width + ':' + height); + } catch (e) { + console.error(e); + } +} + +measureLayout(); +``` + ### Threading Native modules should not have any assumptions about what thread they are being called on, as the current assignment is subject to change in the future. If a blocking call is required, the heavy work should be dispatched to an internally managed worker thread, and any callbacks distributed from there. @@ -259,4 +315,4 @@ componentWillMount: function() { }); } ... -``` \ No newline at end of file +``` diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md index f3b8510c4..b50b82a27 100644 --- a/docs/NativeModulesIOS.md +++ b/docs/NativeModulesIOS.md @@ -173,6 +173,42 @@ A native module is supposed to invoke its callback only once. It can, however, s If you want to pass error-like objects to JavaScript, use `RCTMakeError` from [`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h). Right now this just passes an Error-shaped dictionary to JavaScript, but we would like to automatically generate real JavaScript `Error` objects in the future. +## Promises + +Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameters of a bridged native method are an `RCTPromiseResolveBlock` and `RCTPromiseRejectBlock`, its corresponding JS method will return a JS Promise object. + +Refactoring the above code to use a promise instead of callbacks looks like this: + +```objective-c +RCT_REMAP_METHOD(findEvents, + resolver:(RCTPromiseResolveBlock)resolve, + rejecter:(RCTPromiseRejectBlock)reject)) +{ + NSArray *events = ... + if (events) { + resolve(events); + } else { + reject(error); + } +} +``` + +The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result: + +```js +async function updateEvents() { + try { + var events = await CalendarManager.findEvents(); + + this.setState({ events }); + } catch (e) { + console.error(e); + } +} + +updateEvents(); +``` + ## Threading The native module should not have any assumptions about what thread it is being called on. React Native invokes native modules methods on a separate serial GCD queue, but this is an implementation detail and might change. The `- (dispatch_queue_t)methodQueue` method allows the native module to specify which queue its methods should be run on. For example, if it needs to use a main-thread-only iOS API, it should specify this via: