Skip to content

Commit f64f664

Browse files
committed
Attempts to simplify things a little.
1 parent f0bb218 commit f64f664

File tree

1 file changed

+31
-18
lines changed

1 file changed

+31
-18
lines changed

src/coconut/react/View.hx

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ class View extends ViewBase {
1919
return (cast react.React.createElement).apply(null, [react.Fragment, attr].concat(cast children));
2020
}
2121

22-
class ViewBase extends NativeComponent<{ vtree: RenderResult }, {}, ImplicitContext> {
22+
class ViewBase extends NativeComponent<{ revision: Int }, {}, ImplicitContext> {
2323

2424
@:noCompletion var __rendered:Observable<RenderResult>;
2525
@:noCompletion var __binding:Binding;
2626
@:noCompletion var __viewMounted:Void->Void;
2727
@:noCompletion var __viewUpdated:Void->Void;
2828
@:noCompletion var __viewUnmounting:Void->Void;
29+
@:noCompletion var __last:RenderResult;
2930

3031
public function new(
3132
rendered:Observable<RenderResult>,
@@ -34,24 +35,16 @@ class ViewBase extends NativeComponent<{ vtree: RenderResult }, {}, ImplicitCont
3435
unmounting:Void->Void
3536
) {
3637
js.Syntax.code('{0}.call(this)', NativeComponent);
38+
this.__react_state = { revision: 0 };
3739
this.__rendered = rendered;
3840
this.__viewMounted = mounted;
3941
this.__viewUpdated = updated;
4042
this.__viewUnmounting = unmounting;
4143
}
4244

43-
@:noCompletion function __getRender()
44-
return (switch __react_state {
45-
case null: __snap();
46-
case v: v;
47-
}).vtree;
48-
49-
@:noCompletion function __snap():{ vtree: RenderResult }
50-
return { vtree: __rendered.value };
5145

52-
@:keep @:noCompletion @:final function componentDidMount() {
46+
@:keep @:noCompletion @:final function componentDidMount()
5347
if (__viewMounted != null) __viewMounted();
54-
}
5548

5649
@:keep @:noCompletion @:final function componentDidUpdate(_, _)
5750
if (__viewUpdated != null) __viewUpdated();
@@ -66,14 +59,33 @@ class ViewBase extends NativeComponent<{ vtree: RenderResult }, {}, ImplicitCont
6659
if (__viewUnmounting != null) __viewUnmounting();
6760
}
6861

69-
@:keep @:noCompletion @:final function shouldComponentUpdate(_, next:{ vtree: RenderResult })
70-
return __getRender() != next.vtree;
62+
function __getRender()
63+
return Observable.untracked(() -> (__rendered:ObservableObject<RenderResult>).getValue());
64+
65+
@:keep @:noCompletion @:final function shouldComponentUpdate(_, _)
66+
return __last != __getRender();
7167

7268
@:keep @:noCompletion @:final @:native('render') function reactRender() {
73-
if (this.__binding == null) {
69+
/*
70+
Creating the binding in render is meh ...
71+
Before, this was done in componentDidMount, but that means that children bind before parents which leads to
72+
weird rendering order https://github.com/MVCoconut/coconut.react-dom/issues/8
73+
74+
Another seemingly good place would be the constructor,
75+
but there are two issues with that:
76+
77+
1. Apparently the React Context is not yet available
78+
2. I remember coming across a section in the React docs suggesting that React may well instantiate a view and yet
79+
choose not to mount it (because concurrent mode can do wondrous things).
80+
81+
So all in all, this is the least troublesome place to wire up things (╯°□°)╯︵ ┻━┻
82+
83+
So long as the constructor of Binding doesn't mess with the state, it should actually be safe to do.
84+
*/
85+
if (this.__binding == null)
7486
this.__binding = new Binding(this);
75-
}
76-
return switch __getRender() {
87+
88+
return switch __last = __getRender() {
7789
case js.Syntax.typeof(_) => 'undefined': null;
7890
case v: v;
7991
}
@@ -146,14 +158,15 @@ class ViewBase extends NativeComponent<{ vtree: RenderResult }, {}, ImplicitCont
146158
}
147159
}
148160

149-
private class Binding {
161+
private class Binding {//TODO: try to make this an Invalidatable and use the actual Revision ... the last attempt led to infinite recursion though ¯\_(ツ)_/¯
150162

151163
final target:ViewBase;
152164
final link:CallbackLink;
153165

154166
public function new(target) @:privateAccess {
155167
this.target = target;
156-
this.link = target.__rendered.bind(_ -> target.__react_setState(target.__snap()));
168+
var first = true;
169+
this.link = target.__rendered.bind(_ -> if (first) first = false else target.__react_setState({ revision: target.__react_state.revision + 1 }));
157170
}
158171

159172
public function destroy()

0 commit comments

Comments
 (0)