@@ -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