ReactNative External Binding To DedicatedServiceWorker Instead of Class

I thought I’d make a video of it, as it can be faster than pasting code.

Feel free to pause and look at the code along the way.

But basically, the instantiated class is not bound correctly.

—> Link to vid - Screen Recording 2021-12-09...

I’m not positive this is a ReScript problem, it might be a problem with ReactNative; as the this binds to DedicatedWorkerGlobalScope.

I’m new to ReScript, can someone sanity check the following binding?

Note that the class is exported already instantiated.

class BackgroundTimer {

constructor() {
   // etc
}

setTimeout(callback, timeout) {
   // etc
}

}

export default new BackgroundTimer()

And so my binding would be:

type intervalId = int

type t = {
    constructor: unit => unit,
    setTimeout: (unit => unit, int) => intervalId,
}

@module("react-native-background-timer") external backgroundTimer: t = "default"

If this binding is correct…

I might approach this problem more from the RN / Metro Bundler end.

I can also fix the js module in question by adding to the constructor a little.

rescript tries to curry your external function, that’s where the problem occurs.

You have two options,
rescript offers some helpers for object method bindings :

// ReactNativeBackgroundTimer.res
type t

@module("react-native-background-timer")
external backgroundTimer: t = "default"

@send
external runBackgroundTimer: (t, unit => unit, int) => int = "runBackgroundTimer"


// other file
  let timeoutId =
    ReactNativeBackgroundTimer.backgroundTimer->ReactNativeBackgroundTimer.runBackgroundTimer(
      () => Js.log("hi"),
      3000,
    )

or if you want to use record syntax (I don’t like this)

// ReactNativeBackgroundTimer.res
type t = {runBackgroundTimer: (. unit => unit, int) => int}

@module("react-native-background-timer")
external backgroundTimer: t = "default"


//other file
  let timeoutId = ReactNativeBackgroundTimer.backgroundTimer.runBackgroundTimer(.
    () => Js.log("hi"),
    3000,
  )

side note: if the timeout id returned by this module is an actual js engine timeout id you can use Js.Global.timeoutId type

2 Likes

Sweet, it works, thanks! :fire: :fist_right:

I’m not sure I’m at 100% understanding.

In the first example, the type (t) at the begging of runBackgroundTimer’s type signature… is later getting piped in through ReactNativeBackgroundTimer.backgroundTimer->.

Is that an accurate way to describe it?

The trickiest thing about this language so far has been wrapping my head around bindings… (long time JS developer).

1 Like

I read it like:
"
There is a record type t with a runBackgroundTimer field that is a function taking a callback and a timeout and returns an id.

One instance of this record is exported by react-native-background-timer as default

To start a timer, call runBackgroundTimer on the record from above.
"

1 Like

I have a habit of bringing the function up to the top level in the module youre writing since the outer record isnt much use to anyone:

let runBackgroundTimer = backgroundTimer.runBackgroundTimer
1 Like

That’s a way to model objects with methods in rescript.
first you declare a type with no details type t (it’s called an opaque type) that’s the type of your object you want to bind.

then in order to call methods on that object you should use external functions with @send and object type as their first parameter.

there are other helpers to work with objects such as @new @get @set take a look at this page in docs.

1 Like