@viewfly/core 0.0.1-alpha.6 → 0.0.1-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bundles/index.js CHANGED
@@ -48,25 +48,29 @@ const jsxErrorFn = makeError('JSX');
48
48
  const Fragment = function Fragment() {
49
49
  throw jsxErrorFn('Fragment does not support calling.');
50
50
  };
51
- function jsx(setup, config) {
51
+ function jsx(setup, config, key) {
52
52
  if (typeof setup === 'string') {
53
- return new JSXElement(setup, config);
53
+ return new JSXElement(setup, config, key);
54
54
  }
55
55
  return new JSXComponent(function (context) {
56
- return new Component(context, setup, config);
56
+ return new Component(context, setup, config, key);
57
57
  });
58
58
  }
59
- function jsxs(setup, config) {
59
+ function jsxs(setup, config, key) {
60
60
  if (typeof setup === 'string') {
61
- return new JSXElement(setup, config);
61
+ return new JSXElement(setup, config, key);
62
62
  }
63
63
  return new JSXComponent(function (context) {
64
- return new Component(context, setup, config);
64
+ return new Component(context, setup, config, key);
65
65
  });
66
66
  }
67
67
  class JSXText {
68
68
  constructor(text) {
69
69
  this.text = text;
70
+ this.$$typeOf = '#text';
71
+ }
72
+ is(target) {
73
+ return target.$$typeOf === this.$$typeOf;
70
74
  }
71
75
  }
72
76
  function flatChildren(jsxNodes) {
@@ -91,7 +95,7 @@ class Props {
91
95
  constructor(props) {
92
96
  this.attrs = new Map();
93
97
  this.styles = new Map();
94
- this.classes = new Set();
98
+ this.classes = '';
95
99
  this.listeners = {};
96
100
  this.children = [];
97
101
  if (!props) {
@@ -110,7 +114,7 @@ class Props {
110
114
  return;
111
115
  }
112
116
  if (key === 'class') {
113
- this.classes = new Set(Props.classToArray(props[key]));
117
+ this.classes = Props.classToString(props[key]);
114
118
  return;
115
119
  }
116
120
  if (key === 'style') {
@@ -143,6 +147,31 @@ class Props {
143
147
  this.attrs.set(key, props[key]);
144
148
  });
145
149
  }
150
+ static classToString(config) {
151
+ if (!config) {
152
+ return '';
153
+ }
154
+ if (typeof config === 'string') {
155
+ return config;
156
+ }
157
+ else if (Array.isArray(config)) {
158
+ return config.map(i => {
159
+ return Props.classToString(i);
160
+ }).join(' ');
161
+ }
162
+ else if (typeof config === 'object') {
163
+ if (config.toString !== Object.prototype.toString && !config.toString.toString().includes('[native code]')) {
164
+ return config.toString();
165
+ }
166
+ const classes = [];
167
+ for (const key in config) {
168
+ if ({}.hasOwnProperty.call(config, key) && config[key]) {
169
+ classes.push(key);
170
+ }
171
+ }
172
+ return classes.join(' ');
173
+ }
174
+ }
146
175
  static classToArray(config) {
147
176
  const classes = [];
148
177
  if (!config) {
@@ -172,11 +201,16 @@ class Props {
172
201
  }
173
202
  }
174
203
  class JSXElement {
175
- constructor(name, config) {
204
+ constructor(name, config, key) {
176
205
  this.name = name;
177
206
  this.config = config;
207
+ this.key = key;
208
+ this.$$typeOf = this.name;
178
209
  this.props = new Props(config);
179
210
  }
211
+ is(target) {
212
+ return target.$$typeOf === this.$$typeOf;
213
+ }
180
214
  }
181
215
 
182
216
  const componentSetupStack = [];
@@ -213,10 +247,12 @@ class Component extends di.ReflectiveInjector {
213
247
  get changed() {
214
248
  return this._changed;
215
249
  }
216
- constructor(context, setup, config) {
250
+ constructor(context, setup, config, key) {
217
251
  super(context, []);
218
252
  this.setup = setup;
219
253
  this.config = config;
254
+ this.key = key;
255
+ this.$$typeOf = this.setup;
220
256
  this.destroyCallbacks = [];
221
257
  this.mountCallbacks = [];
222
258
  this.propsChangedCallbacks = [];
@@ -229,6 +265,9 @@ class Component extends di.ReflectiveInjector {
229
265
  this.props = new Props(config);
230
266
  this.parentComponent = this.parentInjector;
231
267
  }
268
+ is(target) {
269
+ return target.$$typeOf === this.$$typeOf;
270
+ }
232
271
  addProvide(providers) {
233
272
  providers = Array.isArray(providers) ? providers : [providers];
234
273
  providers.forEach(p => {
@@ -634,21 +673,6 @@ function getObjectChanges(target, source) {
634
673
  remove: [],
635
674
  add: []
636
675
  };
637
- // if (!target) {
638
- // if (source) {
639
- // Object.keys(source).forEach(key => {
640
- // changes.remove.push([key, source[key]])
641
- // })
642
- // }
643
- // return changes
644
- // }
645
- //
646
- // if (!source) {
647
- // Object.keys(target).forEach(key => {
648
- // changes.add.push([key, target[key]])
649
- // })
650
- // return changes
651
- // }
652
676
  Object.keys(target).forEach(key => {
653
677
  const leftValue = target[key];
654
678
  if (!Reflect.has(source, key)) {
@@ -674,20 +698,6 @@ function getMapChanges(target, source) {
674
698
  remove: [],
675
699
  set: []
676
700
  };
677
- // if (!target) {
678
- // if (source) {
679
- // source.forEach((value, key) => {
680
- // changes.remove.push([key, value])
681
- // })
682
- // }
683
- // return changes
684
- // }
685
- // if (!source) {
686
- // target.forEach((value, key) => {
687
- // changes.set.push([key, value])
688
- // })
689
- // return changes
690
- // }
691
701
  target.forEach((value, key) => {
692
702
  const rightValue = source.get(key);
693
703
  if (value === rightValue) {
@@ -709,58 +719,22 @@ function getMapChanges(target, source) {
709
719
  });
710
720
  return changes;
711
721
  }
712
- function getSetChanges(target, source) {
713
- const changes = {
714
- add: [],
715
- remove: []
716
- };
717
- // if (!target) {
718
- // if (source) {
719
- // source.forEach(i => {
720
- // changes.remove.push(i)
721
- // })
722
- // }
723
- // return changes
724
- // }
725
- //
726
- // if (!source) {
727
- // target.forEach(i => {
728
- // changes.add.push(i)
729
- // })
730
- // return changes
731
- // }
732
- target.forEach(i => {
733
- if (!source.has(i)) {
734
- changes.add.push(i);
735
- }
736
- });
737
- source.forEach(i => {
738
- if (!target.has(i)) {
739
- changes.remove.push(i);
740
- }
741
- });
742
- return changes;
743
- }
744
- const compareText = '0'.repeat(8);
722
+ const compareText = '0'.repeat(6);
745
723
  function getNodeChanges(newVNode, oldVNode) {
746
724
  const newProps = newVNode.props;
747
725
  const oldProps = oldVNode.props;
748
726
  const styleChanges = getMapChanges(newProps.styles, oldProps.styles);
749
727
  const attrChanges = getMapChanges(newProps.attrs, oldProps.attrs);
750
- const classesChanges = getSetChanges(newProps.classes, oldProps.classes);
751
728
  const listenerChanges = getObjectChanges(newProps.listeners, oldProps.listeners);
752
729
  return {
753
730
  styleChanges,
754
731
  attrChanges,
755
- classesChanges,
756
732
  listenerChanges,
757
733
  isChanged: [
758
734
  attrChanges.set.length,
759
735
  attrChanges.remove.length,
760
736
  styleChanges.set.length,
761
737
  styleChanges.remove.length,
762
- classesChanges.add.length,
763
- classesChanges.remove.length,
764
738
  listenerChanges.add.length,
765
739
  listenerChanges.remove.length
766
740
  ].join('') !== compareText
@@ -786,10 +760,10 @@ exports.Renderer = class Renderer {
786
760
  }
787
761
  render() {
788
762
  const { component, host } = this.rootComponentRef;
789
- const chain = new Atom(component, null);
790
- const children = this.buildView(chain);
791
- children.forEach(child => {
792
- this.nativeRenderer.appendChild(host, child);
763
+ const atom = new Atom(component, null);
764
+ this.buildView(atom, {
765
+ isParent: true,
766
+ host
793
767
  });
794
768
  }
795
769
  refresh() {
@@ -867,81 +841,149 @@ exports.Renderer = class Renderer {
867
841
  else {
868
842
  atom.child = null;
869
843
  }
870
- this.diff(atom.child, diffAtom, context);
844
+ this.diff(atom.child, diffAtom, context, 0, 0);
871
845
  component.rendered();
872
846
  }
873
- diff(start, diffAtom, context) {
847
+ diff(newAtom, oldAtom, context, expectIndex, index) {
874
848
  const oldChildren = [];
875
- while (diffAtom) {
876
- oldChildren.push(diffAtom);
877
- diffAtom = diffAtom.sibling;
849
+ while (oldAtom) {
850
+ oldChildren.push({
851
+ index,
852
+ atom: oldAtom
853
+ });
854
+ oldAtom = oldAtom.sibling;
855
+ index++;
878
856
  }
879
857
  const commits = [];
880
- const addReuseCommit = (start, reusedAtom) => {
881
- commits.push(() => {
882
- const isComponent = start.jsxNode instanceof Component;
883
- if (!isComponent) {
884
- const host = context.host;
885
- if (context.isParent) {
886
- this.nativeRenderer.prependChild(host, start.nativeNode);
858
+ const changeCommits = {
859
+ reuseComponent: (start, reusedAtom, expectIndex, diffIndex) => {
860
+ commits.push(() => {
861
+ const { isChanged } = getNodeChanges(start.jsxNode, reusedAtom.jsxNode);
862
+ if (isChanged) {
863
+ reusedAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
887
864
  }
888
- else {
889
- this.nativeRenderer.insertAfter(start.nativeNode, host);
865
+ const newProps = start.jsxNode.props;
866
+ start.jsxNode = reusedAtom.jsxNode;
867
+ start.jsxNode.props = newProps;
868
+ const { render } = this.componentAtomCaches.get(start.jsxNode);
869
+ const template = render();
870
+ if (template) {
871
+ this.linkTemplate(template, start.jsxNode, start);
890
872
  }
891
- context.host = start.nativeNode;
892
- context.isParent = false;
893
- }
894
- if (start.child) {
895
- const childContext = start.jsxNode instanceof JSXElement ? {
896
- host: start.nativeNode,
897
- isParent: true
898
- } : context;
899
- this.diff(start.child, reusedAtom.child, childContext);
900
- }
901
- else if (reusedAtom.child) {
902
- let atom = reusedAtom.child;
903
- while (atom) {
904
- this.cleanView(atom, false);
905
- atom = atom.sibling;
873
+ this.componentAtomCaches.set(start.jsxNode, {
874
+ render,
875
+ atom: start
876
+ });
877
+ if (start.child) {
878
+ this.diff(start.child, reusedAtom.child, context, expectIndex, diffIndex);
879
+ }
880
+ else if (reusedAtom.child) {
881
+ let atom = reusedAtom.child;
882
+ while (atom) {
883
+ this.cleanView(atom, false);
884
+ atom = atom.sibling;
885
+ }
906
886
  }
907
- }
908
- if (isComponent) {
909
887
  start.jsxNode.rendered();
910
- }
911
- });
912
- };
913
- const addCreateCommit = (start) => {
914
- commits.push(() => {
915
- const children = this.createViewByAtom(start);
916
- children.forEach(child => {
917
- if (context.isParent) {
918
- this.nativeRenderer.prependChild(context.host, child);
888
+ });
889
+ },
890
+ reuseElement: (newAtom, oldAtom, expectIndex, oldIndex) => {
891
+ commits.push(() => {
892
+ newAtom.nativeNode = oldAtom.nativeNode;
893
+ const host = context.host;
894
+ if (expectIndex !== oldIndex) {
895
+ if (context.isParent) {
896
+ this.nativeRenderer.prependChild(host, newAtom.nativeNode);
897
+ }
898
+ else {
899
+ this.nativeRenderer.insertAfter(newAtom.nativeNode, host);
900
+ }
919
901
  }
920
- else {
921
- this.nativeRenderer.insertAfter(child, context.host);
902
+ context.host = newAtom.nativeNode;
903
+ context.isParent = false;
904
+ const applyRefs = this.updateNativeNodeProperties(newAtom.jsxNode, oldAtom.jsxNode, newAtom.nativeNode);
905
+ if (newAtom.child) {
906
+ this.diff(newAtom.child, oldAtom.child, {
907
+ host: newAtom.nativeNode,
908
+ isParent: true
909
+ }, 0, 0);
922
910
  }
923
- context.host = child;
911
+ else if (oldAtom.child) {
912
+ let atom = oldAtom.child;
913
+ while (atom) {
914
+ this.cleanView(atom, false);
915
+ atom = atom.sibling;
916
+ }
917
+ }
918
+ if (applyRefs) {
919
+ applyRefs();
920
+ }
921
+ });
922
+ },
923
+ reuseText: (newAtom, oldAtom) => {
924
+ commits.push(() => {
925
+ const nativeNode = oldAtom.nativeNode;
926
+ if (newAtom.jsxNode.text !== oldAtom.jsxNode.text) {
927
+ this.nativeRenderer.syncTextContent(nativeNode, newAtom.jsxNode.text);
928
+ }
929
+ newAtom.nativeNode = nativeNode;
930
+ context.host = nativeNode;
924
931
  context.isParent = false;
925
932
  });
926
- });
927
- };
928
- while (start && !start.nativeNode) {
929
- const reusedAtom = this.reuseAndUpdate(start, oldChildren);
930
- if (reusedAtom) {
931
- addReuseCommit(start, reusedAtom);
932
- }
933
- else {
934
- addCreateCommit(start);
933
+ },
934
+ create: (start) => {
935
+ commits.push(() => {
936
+ this.buildView(start, context);
937
+ });
935
938
  }
936
- start = start.sibling;
939
+ };
940
+ while (newAtom && !newAtom.nativeNode) {
941
+ this.createChanges(newAtom, expectIndex, oldChildren, changeCommits);
942
+ newAtom = newAtom.sibling;
943
+ expectIndex++;
937
944
  }
938
- for (const atom of oldChildren) {
939
- this.cleanView(atom, false);
945
+ for (const item of oldChildren) {
946
+ this.cleanView(item.atom, false);
940
947
  }
941
- for (const commit of commits) {
948
+ for (let i = 0; i < commits.length; i++) {
949
+ const commit = commits[i];
942
950
  commit();
943
951
  }
944
952
  }
953
+ createChanges(newAtom, lastIndex, oldChildren, changeCommits) {
954
+ let isReuse = false;
955
+ for (let i = 0; i < oldChildren.length; i++) {
956
+ const { atom: diffAtom, index: diffIndex } = oldChildren[i];
957
+ const key = newAtom.jsxNode.key;
958
+ const diffKey = diffAtom.jsxNode.key;
959
+ if (key !== undefined && diffKey !== undefined) {
960
+ if (diffKey !== key) {
961
+ continue;
962
+ }
963
+ isReuse = lastIndex > diffIndex;
964
+ }
965
+ if (newAtom.jsxNode.is(diffAtom.jsxNode)) {
966
+ if (newAtom.jsxNode instanceof JSXElement) {
967
+ if (isReuse) {
968
+ this.nativeRenderer.remove(diffAtom.nativeNode);
969
+ }
970
+ changeCommits.reuseElement(newAtom, diffAtom, lastIndex, diffIndex);
971
+ }
972
+ else if (newAtom.jsxNode instanceof JSXText) {
973
+ changeCommits.reuseText(newAtom, diffAtom);
974
+ }
975
+ else {
976
+ if (isReuse) {
977
+ this.temporarilyRemove(diffAtom);
978
+ }
979
+ changeCommits.reuseComponent(newAtom, diffAtom, lastIndex, diffIndex);
980
+ }
981
+ oldChildren.splice(i, 1);
982
+ return;
983
+ }
984
+ }
985
+ changeCommits.create(newAtom);
986
+ }
945
987
  cleanView(atom, isClean) {
946
988
  if (atom.nativeNode) {
947
989
  if (!isClean) {
@@ -962,148 +1004,74 @@ exports.Renderer = class Renderer {
962
1004
  atom.jsxNode.destroy();
963
1005
  }
964
1006
  }
965
- reuseAndUpdate(start, oldChildren) {
966
- for (let i = 0; i < oldChildren.length; i++) {
967
- const diffAtom = oldChildren[i];
968
- if (start.jsxNode instanceof JSXElement) {
969
- if (diffAtom.jsxNode instanceof JSXElement && start.jsxNode.name === diffAtom.jsxNode.name) {
970
- const nativeNode = diffAtom.nativeNode;
971
- start.nativeNode = nativeNode;
972
- this.updateNativeNodeProperties(start.jsxNode, diffAtom.jsxNode, nativeNode);
973
- oldChildren.splice(i, 1);
974
- return diffAtom;
975
- }
1007
+ temporarilyRemove(atom) {
1008
+ let next = atom.child;
1009
+ while (next) {
1010
+ if (next.jsxNode instanceof Component) {
1011
+ this.temporarilyRemove(next);
976
1012
  }
977
- else if (start.jsxNode instanceof JSXText) {
978
- if (diffAtom.jsxNode instanceof JSXText) {
979
- const nativeNode = diffAtom.nativeNode;
980
- if (start.jsxNode.text !== diffAtom.jsxNode.text) {
981
- this.nativeRenderer.syncTextContent(nativeNode, start.jsxNode.text);
982
- }
983
- start.nativeNode = nativeNode;
984
- oldChildren.splice(i, 1);
985
- return diffAtom;
986
- }
987
- }
988
- else if (diffAtom.jsxNode instanceof Component) {
989
- if (start.jsxNode.setup === diffAtom.jsxNode.setup) {
990
- const { isChanged } = getNodeChanges(start.jsxNode, diffAtom.jsxNode);
991
- if (isChanged) {
992
- diffAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
993
- }
994
- const newProps = start.jsxNode.props;
995
- start.jsxNode = diffAtom.jsxNode;
996
- start.jsxNode.props = newProps;
997
- const { render } = this.componentAtomCaches.get(start.jsxNode);
998
- const template = render();
999
- if (template) {
1000
- this.linkTemplate(template, start.jsxNode, start);
1001
- }
1002
- this.componentAtomCaches.set(start.jsxNode, {
1003
- render,
1004
- atom: start
1005
- });
1006
- oldChildren.splice(i, 1);
1007
- return diffAtom;
1008
- }
1013
+ else {
1014
+ this.nativeRenderer.remove(next.nativeNode);
1009
1015
  }
1016
+ next = next.sibling;
1010
1017
  }
1011
- return null;
1012
1018
  }
1013
- createViewByAtom(atom) {
1014
- if (atom.jsxNode instanceof JSXElement) {
1015
- const nativeNode = this.createElement(atom.jsxNode);
1016
- atom.nativeNode = nativeNode;
1017
- if (atom.child) {
1018
- const children = this.buildView(atom.child);
1019
- for (const child of children) {
1020
- this.nativeRenderer.appendChild(nativeNode, child);
1021
- }
1019
+ buildView(atom, context) {
1020
+ if (atom.jsxNode instanceof Component) {
1021
+ this.componentRender(atom.jsxNode, atom);
1022
+ let child = atom.child;
1023
+ while (child) {
1024
+ this.buildView(child, context);
1025
+ child = child.sibling;
1022
1026
  }
1023
- return [nativeNode];
1027
+ atom.jsxNode.rendered();
1024
1028
  }
1025
- else if (atom.jsxNode instanceof JSXText) {
1026
- const nativeNode = this.createTextNode(atom.jsxNode);
1029
+ else {
1030
+ let nativeNode;
1031
+ let applyRefs = null;
1032
+ if (atom.jsxNode instanceof JSXElement) {
1033
+ const { nativeNode: n, applyRefs: a } = this.createElement(atom.jsxNode);
1034
+ nativeNode = n;
1035
+ applyRefs = a;
1036
+ }
1037
+ else {
1038
+ nativeNode = this.createTextNode(atom.jsxNode);
1039
+ }
1027
1040
  atom.nativeNode = nativeNode;
1028
- return [nativeNode];
1029
- }
1030
- const { template, render } = atom.jsxNode.init();
1031
- this.componentAtomCaches.set(atom.jsxNode, {
1032
- atom,
1033
- render
1034
- });
1035
- if (template) {
1036
- this.linkTemplate(template, atom.jsxNode, atom);
1037
- }
1038
- if (atom.child) {
1039
- return this.buildView(atom.child);
1040
- }
1041
- return [];
1042
- }
1043
- buildView(chain) {
1044
- const context = [];
1045
- const children = [];
1046
- function getContext() {
1047
- return context[context.length - 1];
1048
- }
1049
- let atom = chain;
1050
- const stopAtom = chain.parent;
1051
- wrap: while (atom) {
1052
- if (atom.jsxNode instanceof Component) {
1053
- this.componentRender(atom.jsxNode, atom);
1054
- if (atom.child) {
1055
- atom = atom.child;
1056
- continue;
1057
- }
1058
- atom.jsxNode.rendered();
1041
+ if (context.isParent) {
1042
+ this.nativeRenderer.prependChild(context.host, nativeNode);
1059
1043
  }
1060
1044
  else {
1061
- const host = getContext();
1062
- const nativeNode = atom.jsxNode instanceof JSXElement ? this.createElement(atom.jsxNode) : this.createTextNode(atom.jsxNode);
1063
- atom.nativeNode = nativeNode;
1064
- if (host) {
1065
- this.nativeRenderer.appendChild(host, nativeNode);
1066
- }
1067
- else {
1068
- children.push(nativeNode);
1069
- }
1070
- if (atom.child) {
1071
- context.push(nativeNode);
1072
- atom = atom.child;
1073
- continue;
1074
- }
1045
+ this.nativeRenderer.insertAfter(nativeNode, context.host);
1075
1046
  }
1076
- while (atom) {
1077
- if (atom.sibling) {
1078
- atom = atom.sibling;
1079
- break;
1080
- }
1081
- atom = atom.parent;
1082
- const isComponent = (atom === null || atom === void 0 ? void 0 : atom.jsxNode) instanceof Component;
1083
- if (isComponent) {
1084
- atom.jsxNode.rendered();
1085
- }
1086
- if (atom === stopAtom) {
1087
- break wrap;
1088
- }
1089
- if (isComponent) {
1090
- continue;
1047
+ if (atom.jsxNode instanceof JSXElement) {
1048
+ const childContext = {
1049
+ isParent: true,
1050
+ host: nativeNode
1051
+ };
1052
+ let child = atom.child;
1053
+ while (child) {
1054
+ this.buildView(child, childContext);
1055
+ child = child.sibling;
1091
1056
  }
1092
- context.pop();
1057
+ }
1058
+ context.host = nativeNode;
1059
+ context.isParent = false;
1060
+ if (applyRefs) {
1061
+ applyRefs();
1093
1062
  }
1094
1063
  }
1095
- return children;
1096
1064
  }
1097
- componentRender(component, parent) {
1065
+ componentRender(component, from) {
1098
1066
  const { template, render } = component.init();
1099
1067
  if (template) {
1100
- this.linkTemplate(template, component, parent);
1068
+ this.linkTemplate(template, component, from);
1101
1069
  }
1102
1070
  this.componentAtomCaches.set(component, {
1103
1071
  render,
1104
- atom: parent
1072
+ atom: from
1105
1073
  });
1106
- return parent;
1074
+ return from;
1107
1075
  }
1108
1076
  createChainByComponentFactory(context, factory, parent) {
1109
1077
  const component = factory.createInstance(context);
@@ -1159,34 +1127,39 @@ exports.Renderer = class Renderer {
1159
1127
  createElement(vNode) {
1160
1128
  const nativeNode = this.nativeRenderer.createElement(vNode.name);
1161
1129
  const props = vNode.props;
1162
- if (props) {
1163
- let bindingRefs;
1164
- props.attrs.forEach((value, key) => {
1165
- if (key === refKey) {
1166
- bindingRefs = value;
1167
- return;
1168
- }
1169
- this.nativeRenderer.setProperty(nativeNode, key, value);
1170
- });
1171
- props.styles.forEach((value, key) => {
1172
- this.nativeRenderer.setStyle(nativeNode, key, value);
1173
- });
1174
- props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1175
- Object.keys(props.listeners).forEach(type => {
1176
- this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1177
- });
1178
- this.applyRefs(bindingRefs, nativeNode, true);
1130
+ let bindingRefs;
1131
+ props.attrs.forEach((value, key) => {
1132
+ if (key === refKey) {
1133
+ bindingRefs = value;
1134
+ return;
1135
+ }
1136
+ this.nativeRenderer.setProperty(nativeNode, key, value);
1137
+ });
1138
+ props.styles.forEach((value, key) => {
1139
+ this.nativeRenderer.setStyle(nativeNode, key, value);
1140
+ });
1141
+ if (props.classes) {
1142
+ this.nativeRenderer.setClass(nativeNode, props.classes);
1179
1143
  }
1180
- return nativeNode;
1144
+ Object.keys(props.listeners).forEach(type => {
1145
+ this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1146
+ });
1147
+ return {
1148
+ nativeNode,
1149
+ applyRefs: () => {
1150
+ this.applyRefs(bindingRefs, nativeNode, true);
1151
+ }
1152
+ };
1181
1153
  }
1182
1154
  createTextNode(child) {
1183
1155
  return this.nativeRenderer.createTextNode(child.text);
1184
1156
  }
1185
1157
  updateNativeNodeProperties(newVNode, oldVNode, nativeNode) {
1186
- const { styleChanges, attrChanges, classesChanges, listenerChanges, isChanged } = getNodeChanges(newVNode, oldVNode);
1187
- if (!isChanged) {
1188
- return;
1189
- }
1158
+ const newProps = newVNode.props;
1159
+ const oldProps = oldVNode.props;
1160
+ const styleChanges = getMapChanges(newProps.styles, oldProps.styles);
1161
+ const attrChanges = getMapChanges(newProps.attrs, oldProps.attrs);
1162
+ const listenerChanges = getObjectChanges(newProps.listeners, oldProps.listeners);
1190
1163
  styleChanges.remove.forEach(i => this.nativeRenderer.removeStyle(nativeNode, i[0]));
1191
1164
  styleChanges.set.forEach(i => this.nativeRenderer.setStyle(nativeNode, i[0], i[1]));
1192
1165
  let unBindRefs;
@@ -1205,16 +1178,19 @@ exports.Renderer = class Renderer {
1205
1178
  }
1206
1179
  this.nativeRenderer.setProperty(nativeNode, key, value);
1207
1180
  });
1208
- classesChanges.remove.forEach(i => this.nativeRenderer.removeClass(nativeNode, i));
1209
- classesChanges.add.forEach(i => this.nativeRenderer.addClass(nativeNode, i));
1181
+ if (newProps.classes !== oldProps.classes) {
1182
+ this.nativeRenderer.setClass(nativeNode, newProps.classes);
1183
+ }
1210
1184
  listenerChanges.remove.forEach(i => {
1211
1185
  this.nativeRenderer.unListen(nativeNode, i[0], i[1]);
1212
1186
  });
1213
1187
  listenerChanges.add.forEach(i => {
1214
1188
  this.nativeRenderer.listen(nativeNode, i[0], i[1]);
1215
1189
  });
1216
- this.applyRefs(unBindRefs, nativeNode, false);
1217
- this.applyRefs(bindRefs, nativeNode, true);
1190
+ return () => {
1191
+ this.applyRefs(unBindRefs, nativeNode, false);
1192
+ this.applyRefs(bindRefs, nativeNode, true);
1193
+ };
1218
1194
  }
1219
1195
  applyRefs(refs, nativeNode, binding) {
1220
1196
  refs = Array.isArray(refs) ? refs : [refs];