Fork me on GitHub
#cljsrn
<
2017-07-22
>
mfikes15:07:55

I’ve started working on improved coverage of React Native externs. From a few hundred lines to over 12,000 https://github.com/mfikes/react-native-externs/commit/a46b7c34a4e11fb8f197b75884ed084a1b4cb686 I suppose ultimately if this gets mature, it can be submitted to cljsjs

carocad18:07:34

@mfikes you might want to check this project: https://github.com/dmotz/natal-shell He does something similar althuogh I think he crawls the online website for components definitions. Not entirely sure though. Hope it helps 🙂

mfikes15:07:35

A lot of the stuff in the file is props, which I wonder if we even need.

pesterhazy15:07:57

does this work with callback functions?

pesterhazy15:07:34

For example the callback you register wiht addEventListener about halfway through this page: https://facebook.github.io/react-native/releases/next/docs/linking.html

pesterhazy15:07:44

componentDidMount() {
  Linking.addEventListener('url', this._handleOpenURL);
},
componentWillUnmount() {
  Linking.removeEventListener('url', this._handleOpenURL);
},
_handleOpenURL(event) {
  console.log(event.url);
}

pesterhazy15:07:43

you'd still need gobj/get in a cljs version of handlOpenURL right?

mfikes15:07:35

@pesterhazy I’m assuming it would be fine in that whatever you name your handler function is an arbitrary name, and mangling it would not matter as RN only sees the event handler object (it doesn’t call your function by name). I could be wrong, though, because I haven’t been successful in registering AppState callbacks, so, I can’t test. I suppose if you pass a function to React Native such that it will call it by name (which would seem to require passing a string to it), then ^:export would be appropriate when defining the function.

pesterhazy15:07:45

Ah sorry I wasn't clear.. I meant the (.-url m) attribute access you'd need to use in the callback @mfikes

mfikes15:07:55

Ahh, right. I’m assuming it is passing something that looks like #js {:url ""}

pesterhazy15:07:57

I think RN will call the function by reference, so the fn name should be fine

mfikes15:07:29

In that case, I wonder if you can consider the callback value as “data”. Therefore gobj/get is appropriate.

pesterhazy15:07:51

Interesting...

mfikes15:07:28

I’ve been doing this for the data that is passed to animation completion callbacks. It essentially passes you #js {:finished true}

pesterhazy15:07:38

I didn't realize that data vs code was the criterion

mfikes15:07:02

@pesterhazy I think it is an artificial distinction, that I’m starting to appreciate. See https://twitter.com/mfikes/status/882585745424338944

pesterhazy15:07:36

I still think that :js-keys (as opposed to :keys [...]) destructuring would be very useful in such a case

mfikes03:07:41

I wonder if :js-keys has been seriously discussed. Something like

(extend-type object 
  ILookup 
  (-lookup [o k] 
    (goog.object/get o (name k))))
Makes “normal” destructuring on JavaScript objects work, as well as get, get-in, etc., but there’s probably some ill consequences of doing something like that. But :js-keys could be used specifically when you want it, without messing with ILookup for objects.

mfikes03:07:26

I suppose :js-keys is limited in that there is no way to slip it into constructs like (let [{a :a} #js {:a 3}] a)

mfikes03:07:30

Hrm. Maybe ILookup on object is not so bad: https://stackoverflow.com/a/16904181/4284484

pesterhazy10:07:45

Interesting, I didn't know that extending ILookup was so simple. I can't tell if this would have ramifications anywhere else though

pesterhazy10:07:49

I did bring up js-keys some time ago and there didn't seem to be interest in adding it, but maybe a more more formal proposal would be considered

pesterhazy10:07:31

Good point about not being able to rename keys

pesterhazy10:07:35

Would this be possible (let [#js {foo-bar :fooBar} #js {:fooBar 1234}])?

pesterhazy10:07:01

this would use gobj/get internally

pesterhazy10:07:28

Same with (let [#js [head & tail] #js [1 2 3]]) which could use array functions

mfikes13:07:05

Interestingly, extending ILookup to object causes object destructuring to work via the last-ditch native-satisfies? ILookup branch of get, and there are no other native-satisfies? ILookup branches anywhere else in the ClojureScript codebase. (Which argues that it might be fairly safe to do.) Perhaps a cheaper (non-recursive) alternative to outright js->clj is something like

(defn destr [o]
  (reduce (fn [acc k]
            (->> acc
              (cons (goog.object/get o k))
              (cons (keyword k))))
    ()
    (js-keys o)))
as in
(let [{:keys [a b]} (destr #js {:a 1 :b 2})]
  [a b])

mfikes13:07:19

Destructuring on arrays already works, but perhaps in your tail example, you’d like tail to be an array instead of a sequence.

pesterhazy13:07:18

shallow js->clj is a really good idea

pesterhazy13:07:15

true that it works on arrays already

pesterhazy13:07:20

didn't realize that

pesterhazy15:07:00

Thanks for the link, that's very useful

pesterhazy15:07:05

Although it feels somewhat arbitrary given that js doesn't make such a distinction

mfikes16:07:37

Right. I’d like to try an experiment and see what Closure does in this case. If it renames the keys then using externs would be good in case in the future we ever figure out how to pass React Native through Closure and want to eliminate the mechanisms we have to prevent mangling without actually changing code.

mfikes16:07:20

I'll add externs to cover objects passed to callbacks; I'm sure this is the right thing to do (in order words, not treat the objects as data—they will be subjected to mangling unless truly constructed using strings)

pesterhazy16:07:54

out of curiosity, how do you specify externs in that case?

pesterhazy16:07:13

Is there an "object" to attach them to?

mfikes16:07:38

I think the var name in the file would be arbitrary—perhaps long and unique and meaningful to humans

pesterhazy16:07:06

aha, so the attribute names are actually global?

pesterhazy16:07:20

I.e. if I define React.renderComponent as an extern, myObject.renderComponent will also be guarded against minification?