Skip to content

Commit

Permalink
New subscription API (#202)
Browse files Browse the repository at this point in the history
* New subscription API

Partially addresses #173

Name pending (don't use it in prod ofc).

* Change register to onUnmount
  • Loading branch information
chenglou committed Mar 28, 2018
1 parent 3df5d89 commit 5074a17
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 17 deletions.
55 changes: 44 additions & 11 deletions lib/js/src/ReasonReact.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';

var List = require("bs-platform/lib/js/list.js");
var Curry = require("bs-platform/lib/js/curry.js");
var React = require("react");
var Caml_builtin_exceptions = require("bs-platform/lib/js/caml_builtin_exceptions.js");
Expand Down Expand Up @@ -86,6 +85,22 @@ function convertPropsIfTheyreFromJs(props, jsPropsToReason, debugName) {
}
}

function arrayOfList(l) {
var _l = l;
var acc = /* array */[];
while(true) {
var l$1 = _l;
if (l$1) {
acc.push(l$1[0]);
_l = l$1[1];
continue ;

} else {
return acc.reverse();
}
};
}

function createClass(debugName) {
return ReasonReactOptimizedCreateClass.createClass({
displayName: debugName,
Expand All @@ -97,7 +112,8 @@ function createClass(debugName) {
/* reduce */$$this.reduceMethod,
/* state */state,
/* retainedProps */retainedProps,
/* send */$$this.sendMethod
/* send */$$this.sendMethod,
/* onUnmount */$$this.registerMethod
];
}),
transitionNextTotalState: (function (curTotalState, reasonStateUpdate) {
Expand Down Expand Up @@ -176,13 +192,13 @@ function createClass(debugName) {
var curReasonState = curTotalState.reasonState;
var self = $$this.self(curReasonState, component[/* retainedProps */11]);
if (component[/* subscriptions */13] !== subscriptionsDefault) {
var subscriptions = List.map((function (param) {
var subscriptions = arrayOfList(Curry._1(component[/* subscriptions */13], self)).map((function (param) {
var unsubscribe = param[1];
var token = Curry._1(param[0], /* () */0);
return (function () {
return Curry._1(unsubscribe, token);
});
}), Curry._1(component[/* subscriptions */13], self));
}));
$$this.subscriptions = subscriptions;
}
if (component[/* didMount */4] !== lifecycleNoUpdate) {
Expand Down Expand Up @@ -231,12 +247,14 @@ function createClass(debugName) {
var oldSelf_001 = /* reduce */newSelf[/* reduce */1];
var oldSelf_003 = /* retainedProps */oldConvertedReasonProps[0][/* retainedProps */11];
var oldSelf_004 = /* send */newSelf[/* send */4];
var oldSelf_005 = /* onUnmount */newSelf[/* onUnmount */5];
var oldSelf = /* record */[
oldSelf_000,
oldSelf_001,
/* state */prevReasonState,
oldSelf_003,
oldSelf_004
oldSelf_004,
oldSelf_005
];
return Curry._1(newComponent[/* didUpdate */5], /* record */[
/* oldSelf */oldSelf,
Expand All @@ -257,12 +275,13 @@ function createClass(debugName) {
Curry._1(component[/* willUnmount */6], $$this.self(curReasonState, component[/* retainedProps */11]));
}
var match = $$this.subscriptions;
if (match == null) {
if (match !== null) {
match.forEach((function (unsubscribe) {
return Curry._1(unsubscribe, /* () */0);
}));
return /* () */0;
} else {
return List.iter((function (unsubscribe) {
return Curry._1(unsubscribe, /* () */0);
}), List.rev(match));
return /* () */0;
}
}),
componentWillUpdate: (function (nextProps, nextState) {
Expand All @@ -282,12 +301,14 @@ function createClass(debugName) {
var oldSelf_001 = /* reduce */newSelf[/* reduce */1];
var oldSelf_003 = /* retainedProps */oldConvertedReasonProps[0][/* retainedProps */11];
var oldSelf_004 = /* send */newSelf[/* send */4];
var oldSelf_005 = /* onUnmount */newSelf[/* onUnmount */5];
var oldSelf = /* record */[
oldSelf_000,
oldSelf_001,
/* state */curReasonState,
oldSelf_003,
oldSelf_004
oldSelf_004,
oldSelf_005
];
return Curry._1(newComponent[/* willUpdate */7], /* record */[
/* oldSelf */oldSelf,
Expand Down Expand Up @@ -351,12 +372,14 @@ function createClass(debugName) {
var oldSelf_001 = /* reduce */newSelf[/* reduce */1];
var oldSelf_003 = /* retainedProps */oldConvertedReasonProps[0][/* retainedProps */11];
var oldSelf_004 = /* send */newSelf[/* send */4];
var oldSelf_005 = /* onUnmount */newSelf[/* onUnmount */5];
var oldSelf = /* record */[
oldSelf_000,
oldSelf_001,
/* state */curReasonState,
oldSelf_003,
oldSelf_004
oldSelf_004,
oldSelf_005
];
ret = Curry._1(newComponent[/* shouldUpdate */8], /* record */[
/* oldSelf */oldSelf,
Expand All @@ -368,6 +391,16 @@ function createClass(debugName) {
nextState.reasonStateVersionUsedToComputeSubelements = nextReasonStateVersion;
return ret;
}),
registerMethod: (function (subscription) {
var $$this = this ;
var match = $$this.subscriptions;
if (match !== null) {
match.push(subscription);
return /* () */0;
} else {
return $$this.subscriptions = /* array */[subscription];
}
}),
handleMethod: (function (callback) {
var $$this = this ;
var thisJs = (this);
Expand Down
32 changes: 26 additions & 6 deletions src/ReasonReact.re
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ and self('state, 'retainedProps, 'action) = {
state: 'state,
retainedProps: 'retainedProps,
send: 'action => unit,
onUnmount: (unit => unit) => unit,
}
and oldNewSelf('state, 'retainedProps, 'action) = {
oldSelf: self('state, 'retainedProps, 'action),
Expand Down Expand Up @@ -247,14 +248,27 @@ let convertPropsIfTheyreFromJs = (props, jsPropsToReason, debugName) => {
};
};

/* This prepares us to remove our dependency on List, which shrinks
ReasonReact dramatically and makes it adoptible on some codebases with tightly enforced size constraints */
let arrayOfList = l => {
let rec arrayOfList = (l, acc) =>
switch (l) {
| [] => Js.Array.reverseInPlace(acc)
| [head, ...rest] =>
ignore(Js.Array.push(head, acc));
arrayOfList(rest, acc);
};
arrayOfList(l, [||]);
};

let createClass =
(type reasonState, type retainedProps, type action, debugName)
: reactClass =>
ReasonReactOptimizedCreateClass.createClass(.
[@bs]
{
val displayName = debugName;
val mutable subscriptions = Js.Nullable.null;
val mutable subscriptions = Js.null;
/***
* TODO: Avoid allocating this every time we need it. Should be doable.
*/
Expand All @@ -264,6 +278,7 @@ let createClass =
reduce: Obj.magic(this##reduceMethod),
state,
retainedProps,
onUnmount: Obj.magic(this##registerMethod),
};
/***
* TODO: Null out fields that aren't overridden beyond defaults in
Expand Down Expand Up @@ -368,11 +383,12 @@ let createClass =
if (component.subscriptions !== subscriptionsDefault) {
let subscriptions =
component.subscriptions(self)
|> List.map((Sub(subscribe, unsubscribe)) => {
|> arrayOfList
|> Js.Array.map((Sub(subscribe, unsubscribe)) => {
let token = subscribe();
() => unsubscribe(token);
});
this##subscriptions#=(Js.Nullable.return(subscriptions));
this##subscriptions#=(Js.Null.return(subscriptions));
};
if (component.didMount !== didMountDefault) {
let reasonStateUpdate = component.didMount(self);
Expand Down Expand Up @@ -470,10 +486,9 @@ let createClass =
let self = Obj.magic(self);
component.willUnmount(self);
};
switch (Js.Nullable.toOption(this##subscriptions)) {
switch (Js.Null.toOption(this##subscriptions)) {
| None => ()
| Some(subs) =>
List.rev(subs) |> List.iter(unsubscribe => unsubscribe())
| Some(subs) => Js.Array.forEach(unsubscribe => unsubscribe(), subs)
};
};
/***
Expand Down Expand Up @@ -674,6 +689,11 @@ let createClass =
nextState##reasonStateVersionUsedToComputeSubelements#=nextReasonStateVersion;
ret;
};
pub registerMethod = subscription =>
switch (Js.Null.toOption(this##subscriptions)) {
| None => this##subscriptions#=(Js.Null.return([|subscription|]))
| Some(subs) => ignore(Js.Array.push(subscription, subs))
};
pub handleMethod = callback => {
let thisJs:
jsComponentThis(reasonState, element, retainedProps, action) = [%bs.raw
Expand Down
1 change: 1 addition & 0 deletions src/ReasonReact.rei
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ and self('state, 'retainedProps, 'action) = {
state: 'state,
retainedProps: 'retainedProps,
send: 'action => unit,
onUnmount: (unit => unit) => unit,
};

type reactClassInternal;
Expand Down

0 comments on commit 5074a17

Please sign in to comment.