@viewfly/core 0.0.1-alpha.7 → 0.0.1-alpha.9

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.
@@ -3,10 +3,6 @@ export interface MapChanges {
3
3
  remove: [string, any][];
4
4
  set: [string, any][];
5
5
  }
6
- export interface ArrayChanges {
7
- remove: string[];
8
- add: string[];
9
- }
10
6
  export interface ObjectChanges {
11
7
  remove: [string, any][];
12
8
  add: [string, any][];
@@ -14,11 +10,9 @@ export interface ObjectChanges {
14
10
  export declare const refKey = "ref";
15
11
  export declare function getObjectChanges(target: Record<string, any>, source: Record<string, any>): ObjectChanges;
16
12
  export declare function getMapChanges(target: Map<string, any>, source: Map<string, any>): MapChanges;
17
- export declare function getSetChanges(target: Set<string>, source: Set<string>): ArrayChanges;
18
13
  export declare function getNodeChanges(newVNode: JSXElement | Component, oldVNode: JSXElement | Component): {
19
14
  styleChanges: MapChanges;
20
15
  attrChanges: MapChanges;
21
- classesChanges: ArrayChanges;
22
16
  listenerChanges: ObjectChanges;
23
17
  isChanged: boolean;
24
18
  };
@@ -8,8 +8,7 @@ export declare abstract class NativeRenderer<ElementNode = NativeNode, TextNode
8
8
  abstract removeProperty(node: ElementNode, key: string): void;
9
9
  abstract setStyle(target: ElementNode, key: string, value: any): void;
10
10
  abstract removeStyle(target: ElementNode, key: string): void;
11
- abstract addClass(target: ElementNode, name: string): void;
12
- abstract removeClass(target: ElementNode, name: string): void;
11
+ abstract setClass(target: ElementNode, value: string): void;
13
12
  abstract listen<T = any>(node: ElementNode, type: string, callback: (ev: T) => any): void;
14
13
  abstract unListen(node: ElementNode, type: string, callback: (ev: any) => any): void;
15
14
  abstract remove(node: ElementNode | TextNode): void;
@@ -16,13 +16,12 @@ export declare class Renderer {
16
16
  private reconcileElement;
17
17
  private applyChanges;
18
18
  private diff;
19
+ private createChanges;
19
20
  private cleanView;
20
- private reuseAndUpdate;
21
- private temporarilyRemove;
22
21
  private buildView;
23
22
  private componentRender;
24
23
  private createChainByComponentFactory;
25
- private createChain;
24
+ private createChainByTemplate;
26
25
  private createChainByJSXElement;
27
26
  private createChainByJSXText;
28
27
  private createChainByChildren;
@@ -66,31 +66,17 @@ function jsxs(setup, config, key) {
66
66
  class JSXText {
67
67
  constructor(text) {
68
68
  this.text = text;
69
+ this.$$typeOf = '#text';
69
70
  }
70
- }
71
- function flatChildren(jsxNodes) {
72
- const children = [];
73
- for (const node of jsxNodes) {
74
- if (node instanceof JSXElement || node instanceof JSXComponent) {
75
- children.push(node);
76
- }
77
- else if (typeof node === 'string' && node.length) {
78
- children.push(new JSXText(node));
79
- }
80
- else if (Array.isArray(node)) {
81
- children.push(...flatChildren(node));
82
- }
83
- else if (node !== null && typeof node !== 'undefined') {
84
- children.push(new JSXText(String(node)));
85
- }
71
+ is(target) {
72
+ return target.$$typeOf === this.$$typeOf;
86
73
  }
87
- return children;
88
74
  }
89
75
  class Props {
90
76
  constructor(props) {
91
77
  this.attrs = new Map();
92
78
  this.styles = new Map();
93
- this.classes = new Set();
79
+ this.classes = '';
94
80
  this.listeners = {};
95
81
  this.children = [];
96
82
  if (!props) {
@@ -100,16 +86,16 @@ class Props {
100
86
  if (key === 'children') {
101
87
  if (props.children !== null && typeof props.children !== 'undefined') {
102
88
  if (Array.isArray(props.children)) {
103
- this.children = flatChildren(props.children);
89
+ this.children = props.children;
104
90
  }
105
91
  else {
106
- this.children = flatChildren([props.children]);
92
+ this.children = [props.children];
107
93
  }
108
94
  }
109
95
  return;
110
96
  }
111
97
  if (key === 'class') {
112
- this.classes = new Set(Props.classToArray(props[key]));
98
+ this.classes = Props.classToString(props[key]);
113
99
  return;
114
100
  }
115
101
  if (key === 'style') {
@@ -142,6 +128,31 @@ class Props {
142
128
  this.attrs.set(key, props[key]);
143
129
  });
144
130
  }
131
+ static classToString(config) {
132
+ if (!config) {
133
+ return '';
134
+ }
135
+ if (typeof config === 'string') {
136
+ return config;
137
+ }
138
+ else if (Array.isArray(config)) {
139
+ return config.map(i => {
140
+ return Props.classToString(i);
141
+ }).join(' ');
142
+ }
143
+ else if (typeof config === 'object') {
144
+ if (config.toString !== Object.prototype.toString && !config.toString.toString().includes('[native code]')) {
145
+ return config.toString();
146
+ }
147
+ const classes = [];
148
+ for (const key in config) {
149
+ if ({}.hasOwnProperty.call(config, key) && config[key]) {
150
+ classes.push(key);
151
+ }
152
+ }
153
+ return classes.join(' ');
154
+ }
155
+ }
145
156
  static classToArray(config) {
146
157
  const classes = [];
147
158
  if (!config) {
@@ -175,8 +186,12 @@ class JSXElement {
175
186
  this.name = name;
176
187
  this.config = config;
177
188
  this.key = key;
189
+ this.$$typeOf = this.name;
178
190
  this.props = new Props(config);
179
191
  }
192
+ is(target) {
193
+ return target.$$typeOf === this.$$typeOf;
194
+ }
180
195
  }
181
196
 
182
197
  const componentSetupStack = [];
@@ -218,6 +233,7 @@ class Component extends ReflectiveInjector {
218
233
  this.setup = setup;
219
234
  this.config = config;
220
235
  this.key = key;
236
+ this.$$typeOf = this.setup;
221
237
  this.destroyCallbacks = [];
222
238
  this.mountCallbacks = [];
223
239
  this.propsChangedCallbacks = [];
@@ -230,6 +246,9 @@ class Component extends ReflectiveInjector {
230
246
  this.props = new Props(config);
231
247
  this.parentComponent = this.parentInjector;
232
248
  }
249
+ is(target) {
250
+ return target.$$typeOf === this.$$typeOf;
251
+ }
233
252
  addProvide(providers) {
234
253
  providers = Array.isArray(providers) ? providers : [providers];
235
254
  providers.forEach(p => {
@@ -635,21 +654,6 @@ function getObjectChanges(target, source) {
635
654
  remove: [],
636
655
  add: []
637
656
  };
638
- // if (!target) {
639
- // if (source) {
640
- // Object.keys(source).forEach(key => {
641
- // changes.remove.push([key, source[key]])
642
- // })
643
- // }
644
- // return changes
645
- // }
646
- //
647
- // if (!source) {
648
- // Object.keys(target).forEach(key => {
649
- // changes.add.push([key, target[key]])
650
- // })
651
- // return changes
652
- // }
653
657
  Object.keys(target).forEach(key => {
654
658
  const leftValue = target[key];
655
659
  if (!Reflect.has(source, key)) {
@@ -675,20 +679,6 @@ function getMapChanges(target, source) {
675
679
  remove: [],
676
680
  set: []
677
681
  };
678
- // if (!target) {
679
- // if (source) {
680
- // source.forEach((value, key) => {
681
- // changes.remove.push([key, value])
682
- // })
683
- // }
684
- // return changes
685
- // }
686
- // if (!source) {
687
- // target.forEach((value, key) => {
688
- // changes.set.push([key, value])
689
- // })
690
- // return changes
691
- // }
692
682
  target.forEach((value, key) => {
693
683
  const rightValue = source.get(key);
694
684
  if (value === rightValue) {
@@ -710,58 +700,22 @@ function getMapChanges(target, source) {
710
700
  });
711
701
  return changes;
712
702
  }
713
- function getSetChanges(target, source) {
714
- const changes = {
715
- add: [],
716
- remove: []
717
- };
718
- // if (!target) {
719
- // if (source) {
720
- // source.forEach(i => {
721
- // changes.remove.push(i)
722
- // })
723
- // }
724
- // return changes
725
- // }
726
- //
727
- // if (!source) {
728
- // target.forEach(i => {
729
- // changes.add.push(i)
730
- // })
731
- // return changes
732
- // }
733
- target.forEach(i => {
734
- if (!source.has(i)) {
735
- changes.add.push(i);
736
- }
737
- });
738
- source.forEach(i => {
739
- if (!target.has(i)) {
740
- changes.remove.push(i);
741
- }
742
- });
743
- return changes;
744
- }
745
- const compareText = '0'.repeat(8);
703
+ const compareText = '0'.repeat(6);
746
704
  function getNodeChanges(newVNode, oldVNode) {
747
705
  const newProps = newVNode.props;
748
706
  const oldProps = oldVNode.props;
749
707
  const styleChanges = getMapChanges(newProps.styles, oldProps.styles);
750
708
  const attrChanges = getMapChanges(newProps.attrs, oldProps.attrs);
751
- const classesChanges = getSetChanges(newProps.classes, oldProps.classes);
752
709
  const listenerChanges = getObjectChanges(newProps.listeners, oldProps.listeners);
753
710
  return {
754
711
  styleChanges,
755
712
  attrChanges,
756
- classesChanges,
757
713
  listenerChanges,
758
714
  isChanged: [
759
715
  attrChanges.set.length,
760
716
  attrChanges.remove.length,
761
717
  styleChanges.set.length,
762
718
  styleChanges.remove.length,
763
- classesChanges.add.length,
764
- classesChanges.remove.length,
765
719
  listenerChanges.add.length,
766
720
  listenerChanges.remove.length
767
721
  ].join('') !== compareText
@@ -868,85 +822,151 @@ let Renderer = class Renderer {
868
822
  else {
869
823
  atom.child = null;
870
824
  }
871
- this.diff(atom.child, diffAtom, context);
825
+ this.diff(atom.child, diffAtom, context, 0, 0);
872
826
  component.rendered();
873
827
  }
874
- diff(start, diffAtom, context) {
828
+ diff(newAtom, oldAtom, context, expectIndex, index) {
875
829
  const oldChildren = [];
876
- let index = 0;
877
- while (diffAtom) {
830
+ while (oldAtom) {
878
831
  oldChildren.push({
879
832
  index,
880
- atom: diffAtom
833
+ atom: oldAtom
881
834
  });
882
- diffAtom = diffAtom.sibling;
835
+ oldAtom = oldAtom.sibling;
883
836
  index++;
884
837
  }
885
838
  const commits = [];
886
- const addUpdateCommit = (start, reusedAtom) => {
887
- commits.push(() => {
888
- const isComponent = start.jsxNode instanceof Component;
889
- if (!isComponent) {
890
- const host = context.host;
891
- if (context.isParent) {
892
- this.nativeRenderer.prependChild(host, start.nativeNode);
839
+ const changeCommits = {
840
+ reuseComponent: (start, reusedAtom, expectIndex, diffIndex) => {
841
+ commits.push(() => {
842
+ const { isChanged } = getNodeChanges(start.jsxNode, reusedAtom.jsxNode);
843
+ if (isChanged) {
844
+ reusedAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
893
845
  }
894
- else {
895
- this.nativeRenderer.insertAfter(start.nativeNode, host);
846
+ const newProps = start.jsxNode.props;
847
+ start.jsxNode = reusedAtom.jsxNode;
848
+ start.jsxNode.props = newProps;
849
+ const { render } = this.componentAtomCaches.get(start.jsxNode);
850
+ const template = render();
851
+ if (template) {
852
+ this.linkTemplate(template, start.jsxNode, start);
853
+ }
854
+ this.componentAtomCaches.set(start.jsxNode, {
855
+ render,
856
+ atom: start
857
+ });
858
+ if (start.child) {
859
+ this.diff(start.child, reusedAtom.child, context, expectIndex, diffIndex);
860
+ }
861
+ else if (reusedAtom.child) {
862
+ let atom = reusedAtom.child;
863
+ while (atom) {
864
+ this.cleanView(atom, false);
865
+ atom = atom.sibling;
866
+ }
896
867
  }
897
- context.host = start.nativeNode;
868
+ start.jsxNode.rendered();
869
+ });
870
+ },
871
+ reuseElement: (newAtom, oldAtom, expectIndex, oldIndex) => {
872
+ commits.push((offset) => {
873
+ newAtom.nativeNode = oldAtom.nativeNode;
874
+ const host = context.host;
875
+ if (expectIndex !== oldIndex - offset) {
876
+ if (context.isParent) {
877
+ this.nativeRenderer.prependChild(host, newAtom.nativeNode);
878
+ }
879
+ else {
880
+ this.nativeRenderer.insertAfter(newAtom.nativeNode, host);
881
+ }
882
+ }
883
+ context.host = newAtom.nativeNode;
898
884
  context.isParent = false;
899
- }
900
- let applyRefs = null;
901
- if (start.jsxNode instanceof JSXElement) {
902
- applyRefs = this.updateNativeNodeProperties(start.jsxNode, reusedAtom.jsxNode, start.nativeNode);
903
- }
904
- if (start.child) {
905
- const childContext = start.jsxNode instanceof JSXElement ? {
906
- host: start.nativeNode,
907
- isParent: true
908
- } : context;
909
- this.diff(start.child, reusedAtom.child, childContext);
910
- }
911
- else if (reusedAtom.child) {
912
- let atom = reusedAtom.child;
913
- while (atom) {
914
- this.cleanView(atom, false);
915
- atom = atom.sibling;
885
+ const applyRefs = this.updateNativeNodeProperties(newAtom.jsxNode, oldAtom.jsxNode, newAtom.nativeNode);
886
+ if (newAtom.child) {
887
+ this.diff(newAtom.child, oldAtom.child, {
888
+ host: newAtom.nativeNode,
889
+ isParent: true
890
+ }, 0, 0);
891
+ }
892
+ else if (oldAtom.child) {
893
+ let atom = oldAtom.child;
894
+ while (atom) {
895
+ this.cleanView(atom, false);
896
+ atom = atom.sibling;
897
+ }
916
898
  }
917
- }
918
- if (applyRefs) {
919
899
  applyRefs();
920
- }
921
- if (isComponent) {
922
- start.jsxNode.rendered();
923
- }
924
- });
925
- };
926
- const addCreateCommit = (start) => {
927
- commits.push(() => {
928
- this.buildView(start, context);
929
- });
930
- };
931
- let i = 0;
932
- while (start && !start.nativeNode) {
933
- const reusedAtom = this.reuseAndUpdate(start, i, oldChildren);
934
- if (reusedAtom) {
935
- addUpdateCommit(start, reusedAtom);
936
- }
937
- else {
938
- addCreateCommit(start);
900
+ });
901
+ },
902
+ reuseText: (newAtom, oldAtom) => {
903
+ commits.push(() => {
904
+ const nativeNode = oldAtom.nativeNode;
905
+ if (newAtom.jsxNode.text !== oldAtom.jsxNode.text) {
906
+ this.nativeRenderer.syncTextContent(nativeNode, newAtom.jsxNode.text);
907
+ }
908
+ newAtom.nativeNode = nativeNode;
909
+ context.host = nativeNode;
910
+ context.isParent = false;
911
+ });
912
+ },
913
+ create: (start) => {
914
+ commits.push(() => {
915
+ this.buildView(start, context);
916
+ });
939
917
  }
940
- i++;
941
- start = start.sibling;
918
+ };
919
+ while (newAtom && !newAtom.nativeNode) {
920
+ this.createChanges(newAtom, expectIndex, oldChildren, changeCommits);
921
+ newAtom = newAtom.sibling;
922
+ expectIndex++;
942
923
  }
943
924
  for (const item of oldChildren) {
944
925
  this.cleanView(item.atom, false);
945
926
  }
946
- for (const commit of commits) {
947
- commit();
927
+ let j = 0;
928
+ let offset = 0;
929
+ const len = oldChildren.length;
930
+ for (let i = 0; i < commits.length; i++) {
931
+ const commit = commits[i];
932
+ while (j < len) {
933
+ const current = oldChildren[j];
934
+ if (current.index <= i) {
935
+ offset++;
936
+ j++;
937
+ continue;
938
+ }
939
+ break;
940
+ }
941
+ commit(offset);
948
942
  }
949
943
  }
944
+ createChanges(newAtom, expectIndex, oldChildren, changeCommits) {
945
+ for (let i = 0; i < oldChildren.length; i++) {
946
+ const { atom: diffAtom, index: diffIndex } = oldChildren[i];
947
+ const key = newAtom.jsxNode.key;
948
+ const diffKey = diffAtom.jsxNode.key;
949
+ if (key !== undefined && diffKey !== undefined) {
950
+ if (diffKey !== key) {
951
+ continue;
952
+ }
953
+ }
954
+ if (newAtom.jsxNode.is(diffAtom.jsxNode)) {
955
+ if (newAtom.jsxNode instanceof JSXElement) {
956
+ changeCommits.reuseElement(newAtom, diffAtom, expectIndex, diffIndex);
957
+ }
958
+ else if (newAtom.jsxNode instanceof JSXText) {
959
+ changeCommits.reuseText(newAtom, diffAtom);
960
+ }
961
+ else {
962
+ changeCommits.reuseComponent(newAtom, diffAtom, expectIndex, diffIndex);
963
+ }
964
+ oldChildren.splice(i, 1);
965
+ return;
966
+ }
967
+ }
968
+ changeCommits.create(newAtom);
969
+ }
950
970
  cleanView(atom, isClean) {
951
971
  if (atom.nativeNode) {
952
972
  if (!isClean) {
@@ -967,80 +987,6 @@ let Renderer = class Renderer {
967
987
  atom.jsxNode.destroy();
968
988
  }
969
989
  }
970
- reuseAndUpdate(start, lastIndex, oldChildren) {
971
- let isReuse = false;
972
- for (let i = 0; i < oldChildren.length; i++) {
973
- const { atom: diffAtom, index: diffIndex } = oldChildren[i];
974
- const key = start.jsxNode.key;
975
- const diffKey = diffAtom.jsxNode.key;
976
- if (key !== undefined && diffKey !== undefined) {
977
- if (diffKey !== key) {
978
- continue;
979
- }
980
- isReuse = lastIndex > diffIndex;
981
- }
982
- if (start.jsxNode instanceof JSXElement) {
983
- if (diffAtom.jsxNode instanceof JSXElement && start.jsxNode.name === diffAtom.jsxNode.name) {
984
- const nativeNode = diffAtom.nativeNode;
985
- if (isReuse) {
986
- this.nativeRenderer.remove(nativeNode);
987
- }
988
- start.nativeNode = nativeNode;
989
- oldChildren.splice(i, 1);
990
- return diffAtom;
991
- }
992
- }
993
- else if (start.jsxNode instanceof JSXText) {
994
- if (diffAtom.jsxNode instanceof JSXText) {
995
- const nativeNode = diffAtom.nativeNode;
996
- if (start.jsxNode.text !== diffAtom.jsxNode.text) {
997
- this.nativeRenderer.syncTextContent(nativeNode, start.jsxNode.text);
998
- }
999
- start.nativeNode = nativeNode;
1000
- oldChildren.splice(i, 1);
1001
- return diffAtom;
1002
- }
1003
- }
1004
- else if (diffAtom.jsxNode instanceof Component) {
1005
- if (start.jsxNode.setup === diffAtom.jsxNode.setup) {
1006
- if (isReuse) {
1007
- this.temporarilyRemove(diffAtom);
1008
- }
1009
- const { isChanged } = getNodeChanges(start.jsxNode, diffAtom.jsxNode);
1010
- if (isChanged) {
1011
- diffAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
1012
- }
1013
- const newProps = start.jsxNode.props;
1014
- start.jsxNode = diffAtom.jsxNode;
1015
- start.jsxNode.props = newProps;
1016
- const { render } = this.componentAtomCaches.get(start.jsxNode);
1017
- const template = render();
1018
- if (template) {
1019
- this.linkTemplate(template, start.jsxNode, start);
1020
- }
1021
- this.componentAtomCaches.set(start.jsxNode, {
1022
- render,
1023
- atom: start
1024
- });
1025
- oldChildren.splice(i, 1);
1026
- return diffAtom;
1027
- }
1028
- }
1029
- }
1030
- return null;
1031
- }
1032
- temporarilyRemove(atom) {
1033
- let next = atom.child;
1034
- while (next) {
1035
- if (next.jsxNode instanceof Component) {
1036
- this.temporarilyRemove(next);
1037
- }
1038
- else {
1039
- this.nativeRenderer.remove(next.nativeNode);
1040
- }
1041
- next = next.sibling;
1042
- }
1043
- }
1044
990
  buildView(atom, context) {
1045
991
  if (atom.jsxNode instanceof Component) {
1046
992
  this.componentRender(atom.jsxNode, atom);
@@ -1105,14 +1051,14 @@ let Renderer = class Renderer {
1105
1051
  }
1106
1052
  return new Atom(component, parent);
1107
1053
  }
1108
- createChain(context, template, parent) {
1054
+ createChainByTemplate(context, template, parent) {
1109
1055
  if (template instanceof JSXElement) {
1110
1056
  return this.createChainByJSXElement(context, template, parent);
1111
1057
  }
1112
- if (template instanceof JSXText) {
1113
- return this.createChainByJSXText(template, parent);
1058
+ if (template instanceof JSXComponent) {
1059
+ return this.createChainByComponentFactory(context, template, parent);
1114
1060
  }
1115
- return this.createChainByComponentFactory(context, template, parent);
1061
+ return parent;
1116
1062
  }
1117
1063
  createChainByJSXElement(context, element, parent) {
1118
1064
  const atom = new Atom(element, parent);
@@ -1126,19 +1072,37 @@ let Renderer = class Renderer {
1126
1072
  createChainByChildren(context, children, parent) {
1127
1073
  const atoms = [];
1128
1074
  for (const item of children) {
1129
- const child = this.createChain(context, item, parent);
1130
- if (Array.isArray(child)) {
1131
- atoms.push(...child);
1075
+ if (item instanceof JSXElement) {
1076
+ atoms.push(this.createChainByJSXElement(context, item, parent));
1077
+ continue;
1132
1078
  }
1133
- else {
1134
- atoms.push(child);
1079
+ if (item instanceof JSXComponent) {
1080
+ const childAtom = this.createChainByComponentFactory(context, item, parent);
1081
+ if (Array.isArray(childAtom)) {
1082
+ atoms.push(...childAtom);
1083
+ }
1084
+ else {
1085
+ atoms.push(childAtom);
1086
+ }
1087
+ continue;
1088
+ }
1089
+ if (typeof item === 'string' && item.length) {
1090
+ atoms.push(this.createChainByJSXText(new JSXText(item), parent));
1091
+ continue;
1092
+ }
1093
+ if (Array.isArray(item)) {
1094
+ atoms.push(...this.createChainByChildren(context, item, parent));
1095
+ continue;
1096
+ }
1097
+ if (item !== null && typeof item !== 'undefined') {
1098
+ atoms.push(this.createChainByJSXText(new JSXText(String(item)), parent));
1135
1099
  }
1136
1100
  }
1137
1101
  return atoms;
1138
1102
  }
1139
1103
  linkTemplate(template, component, parent) {
1140
1104
  if (template) {
1141
- const child = this.createChain(component, template, parent);
1105
+ const child = this.createChainByTemplate(component, template, parent);
1142
1106
  this.link(parent, Array.isArray(child) ? child : [child]);
1143
1107
  }
1144
1108
  }
@@ -1163,7 +1127,9 @@ let Renderer = class Renderer {
1163
1127
  props.styles.forEach((value, key) => {
1164
1128
  this.nativeRenderer.setStyle(nativeNode, key, value);
1165
1129
  });
1166
- props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1130
+ if (props.classes) {
1131
+ this.nativeRenderer.setClass(nativeNode, props.classes);
1132
+ }
1167
1133
  Object.keys(props.listeners).forEach(type => {
1168
1134
  this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1169
1135
  });
@@ -1178,10 +1144,11 @@ let Renderer = class Renderer {
1178
1144
  return this.nativeRenderer.createTextNode(child.text);
1179
1145
  }
1180
1146
  updateNativeNodeProperties(newVNode, oldVNode, nativeNode) {
1181
- const { styleChanges, attrChanges, classesChanges, listenerChanges, isChanged } = getNodeChanges(newVNode, oldVNode);
1182
- if (!isChanged) {
1183
- return null;
1184
- }
1147
+ const newProps = newVNode.props;
1148
+ const oldProps = oldVNode.props;
1149
+ const styleChanges = getMapChanges(newProps.styles, oldProps.styles);
1150
+ const attrChanges = getMapChanges(newProps.attrs, oldProps.attrs);
1151
+ const listenerChanges = getObjectChanges(newProps.listeners, oldProps.listeners);
1185
1152
  styleChanges.remove.forEach(i => this.nativeRenderer.removeStyle(nativeNode, i[0]));
1186
1153
  styleChanges.set.forEach(i => this.nativeRenderer.setStyle(nativeNode, i[0], i[1]));
1187
1154
  let unBindRefs;
@@ -1200,8 +1167,9 @@ let Renderer = class Renderer {
1200
1167
  }
1201
1168
  this.nativeRenderer.setProperty(nativeNode, key, value);
1202
1169
  });
1203
- classesChanges.remove.forEach(i => this.nativeRenderer.removeClass(nativeNode, i));
1204
- classesChanges.add.forEach(i => this.nativeRenderer.addClass(nativeNode, i));
1170
+ if (newProps.classes !== oldProps.classes) {
1171
+ this.nativeRenderer.setClass(nativeNode, newProps.classes);
1172
+ }
1205
1173
  listenerChanges.remove.forEach(i => {
1206
1174
  this.nativeRenderer.unListen(nativeNode, i[0], i[1]);
1207
1175
  });