Skip to content

Commit

Permalink
Added docs on using Promisesin Native Modules
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Nov 23, 2015
1 parent 5f226cf commit fdca422
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
60 changes: 58 additions & 2 deletions docs/NativeModulesAndroid.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -259,4 +315,4 @@ componentWillMount: function() {
});
}
...
```
```
36 changes: 36 additions & 0 deletions docs/NativeModulesIOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit fdca422

Please sign in to comment.