@viewfly/core 1.2.1 → 1.2.3

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
@@ -603,79 +603,6 @@ class ReflectiveInjector {
603
603
 
604
604
  const Type = Function;
605
605
 
606
- const refKey = 'ref';
607
- function getObjectChanges(newProps, oldProps) {
608
- const changes = {
609
- remove: [],
610
- add: [],
611
- replace: []
612
- };
613
- for (const key in newProps) {
614
- const leftValue = newProps[key];
615
- const rightValue = oldProps[key];
616
- if (Reflect.has(oldProps, key)) {
617
- if (leftValue !== rightValue) {
618
- changes.replace.push([key, leftValue, rightValue]);
619
- }
620
- continue;
621
- }
622
- changes.add.push([key, leftValue]);
623
- }
624
- for (const key in oldProps) {
625
- if (!Reflect.has(newProps, key)) {
626
- changes.remove.push([key, oldProps[key]]);
627
- }
628
- }
629
- return changes;
630
- }
631
- function classToString(config) {
632
- if (typeof config === 'string') {
633
- return config;
634
- }
635
- if (!config) {
636
- return '';
637
- }
638
- if (Array.isArray(config)) {
639
- const classes = [];
640
- for (const i of config) {
641
- const v = classToString(i);
642
- if (v) {
643
- classes.push(v);
644
- }
645
- }
646
- return classes.join(' ');
647
- }
648
- if (typeof config === 'object') {
649
- if (config.toString !== Object.prototype.toString && !config.toString.toString().includes('[native code]')) {
650
- return config.toString();
651
- }
652
- const classes = [];
653
- for (const key in config) {
654
- if ({}.hasOwnProperty.call(config, key) && config[key]) {
655
- classes.push(key);
656
- }
657
- }
658
- return classes.join(' ');
659
- }
660
- return '';
661
- }
662
- function styleToObject(style) {
663
- if (typeof style !== 'string') {
664
- return style;
665
- }
666
- const obj = {};
667
- style.split(';').map(s => s.split(':')).forEach(v => {
668
- if (!v[0] || !v[1]) {
669
- return;
670
- }
671
- obj[v[0].trim()] = v[1].trim();
672
- });
673
- return obj;
674
- }
675
- const TextAtomType = Symbol('Text');
676
- const ElementAtomType = Symbol('Element');
677
- const ComponentAtomType = Symbol('Component');
678
-
679
606
  class Listener {
680
607
  constructor(effect) {
681
608
  Object.defineProperty(this, "effect", {
@@ -922,109 +849,25 @@ class Component {
922
849
  return this._changed;
923
850
  }
924
851
  constructor(parentComponent, type, props, key) {
925
- Object.defineProperty(this, "parentComponent", {
926
- enumerable: true,
927
- configurable: true,
928
- writable: true,
929
- value: parentComponent
930
- });
931
- Object.defineProperty(this, "type", {
932
- enumerable: true,
933
- configurable: true,
934
- writable: true,
935
- value: type
936
- });
937
- Object.defineProperty(this, "props", {
938
- enumerable: true,
939
- configurable: true,
940
- writable: true,
941
- value: props
942
- });
943
- Object.defineProperty(this, "key", {
944
- enumerable: true,
945
- configurable: true,
946
- writable: true,
947
- value: key
948
- });
949
- Object.defineProperty(this, "instance", {
950
- enumerable: true,
951
- configurable: true,
952
- writable: true,
953
- value: void 0
954
- });
955
- Object.defineProperty(this, "changedSubComponents", {
956
- enumerable: true,
957
- configurable: true,
958
- writable: true,
959
- value: new Set()
960
- });
961
- Object.defineProperty(this, "unmountedCallbacks", {
962
- enumerable: true,
963
- configurable: true,
964
- writable: true,
965
- value: void 0
966
- });
967
- Object.defineProperty(this, "mountCallbacks", {
968
- enumerable: true,
969
- configurable: true,
970
- writable: true,
971
- value: void 0
972
- });
973
- Object.defineProperty(this, "propsChangedCallbacks", {
974
- enumerable: true,
975
- configurable: true,
976
- writable: true,
977
- value: void 0
978
- });
979
- Object.defineProperty(this, "updatedCallbacks", {
980
- enumerable: true,
981
- configurable: true,
982
- writable: true,
983
- value: void 0
984
- });
985
- Object.defineProperty(this, "updatedDestroyCallbacks", {
986
- enumerable: true,
987
- configurable: true,
988
- writable: true,
989
- value: void 0
990
- });
991
- Object.defineProperty(this, "propsChangedDestroyCallbacks", {
992
- enumerable: true,
993
- configurable: true,
994
- writable: true,
995
- value: void 0
996
- });
997
- Object.defineProperty(this, "_dirty", {
998
- enumerable: true,
999
- configurable: true,
1000
- writable: true,
1001
- value: true
1002
- });
1003
- Object.defineProperty(this, "_changed", {
1004
- enumerable: true,
1005
- configurable: true,
1006
- writable: true,
1007
- value: true
1008
- });
1009
- Object.defineProperty(this, "isFirstRendering", {
1010
- enumerable: true,
1011
- configurable: true,
1012
- writable: true,
1013
- value: true
1014
- });
1015
- Object.defineProperty(this, "refs", {
1016
- enumerable: true,
1017
- configurable: true,
1018
- writable: true,
1019
- value: null
1020
- });
1021
- Object.defineProperty(this, "listener", {
1022
- enumerable: true,
1023
- configurable: true,
1024
- writable: true,
1025
- value: new Listener(() => {
1026
- this.markAsDirtied();
1027
- })
852
+ this.parentComponent = parentComponent;
853
+ this.type = type;
854
+ this.props = props;
855
+ this.key = key;
856
+ this.instance = null;
857
+ this.changedSubComponents = new Set();
858
+ this.viewMetadata = null;
859
+ this.unmountedCallbacks = null;
860
+ this.mountCallbacks = null;
861
+ this.propsChangedCallbacks = null;
862
+ this.updatedCallbacks = null;
863
+ this.updatedDestroyCallbacks = null;
864
+ this.propsChangedDestroyCallbacks = null;
865
+ this._dirty = true;
866
+ this._changed = false;
867
+ this.isFirstRendering = true;
868
+ this.refs = null;
869
+ this.listener = new Listener(() => {
870
+ this.markAsDirtied();
1028
871
  });
1029
872
  }
1030
873
  markAsDirtied() {
@@ -1039,7 +882,7 @@ class Component {
1039
882
  return;
1040
883
  }
1041
884
  this._changed = true;
1042
- if (this.parentComponent instanceof Component) {
885
+ if (this.parentComponent) {
1043
886
  this.parentComponent.markAsChanged(this);
1044
887
  }
1045
888
  }
@@ -1085,62 +928,54 @@ class Component {
1085
928
  update(template, this.instance.$portalHost);
1086
929
  this.rendered();
1087
930
  }
1088
- update(newProps, updateChildren, reuseChildren) {
1089
- const oldProps = this.props;
1090
- if (newProps !== oldProps) {
1091
- const { add, remove, replace } = getObjectChanges(newProps, oldProps);
1092
- if (add.length || remove.length || replace.length) {
1093
- this.invokePropsChangedHooks(newProps);
1094
- }
1095
- else if (!this.dirty) {
1096
- this.props = newProps;
1097
- reuseChildren(false);
1098
- this.rendered();
1099
- return;
1100
- }
1101
- const newRefs = toRefs(newProps.ref);
1102
- if (this.refs) {
1103
- for (const oldRef of this.refs) {
1104
- if (!newRefs.includes(oldRef)) {
1105
- oldRef.unBind(this.instance);
1106
- }
931
+ updateProps(newProps) {
932
+ this.invokePropsChangedHooks(newProps);
933
+ const newRefs = toRefs(newProps.ref);
934
+ if (this.refs) {
935
+ for (const oldRef of this.refs) {
936
+ if (!newRefs.includes(oldRef)) {
937
+ oldRef.unBind(this.instance);
1107
938
  }
1108
939
  }
1109
- for (const newRef of newRefs) {
1110
- newRef.bind(this.instance);
1111
- }
1112
- if (newRefs.length) {
1113
- this.refs = newRefs;
1114
- }
1115
940
  }
941
+ for (const newRef of newRefs) {
942
+ newRef.bind(this.instance);
943
+ }
944
+ if (newRefs.length) {
945
+ this.refs = newRefs;
946
+ }
947
+ }
948
+ canUpdate(oldProps, newProps) {
1116
949
  if (typeof this.instance.$useMemo === 'function') {
1117
950
  if (this.instance.$useMemo(newProps, oldProps)) {
1118
- reuseChildren(true);
1119
- this.rendered();
1120
- return;
951
+ return false;
1121
952
  }
1122
953
  }
954
+ return true;
955
+ }
956
+ rerender() {
1123
957
  this.listener.destroy();
1124
958
  pushListener(this.listener);
1125
959
  const template = this.instance.$render();
1126
960
  popListener();
1127
- updateChildren(template);
1128
- this.rendered();
961
+ return template;
1129
962
  }
1130
963
  destroy() {
1131
- var _a, _b, _c;
1132
964
  this.listener.destroy();
1133
- (_a = this.updatedDestroyCallbacks) === null || _a === void 0 ? void 0 : _a.forEach(fn => {
1134
- fn();
1135
- });
1136
- (_b = this.propsChangedDestroyCallbacks) === null || _b === void 0 ? void 0 : _b.forEach(fn => {
1137
- fn();
1138
- });
1139
- (_c = this.unmountedCallbacks) === null || _c === void 0 ? void 0 : _c.forEach(fn => {
1140
- fn();
1141
- });
1142
- if (this.parentComponent instanceof Component) {
1143
- this.parentComponent.changedSubComponents.delete(this);
965
+ if (this.updatedDestroyCallbacks) {
966
+ this.updatedDestroyCallbacks.forEach(fn => {
967
+ fn();
968
+ });
969
+ }
970
+ if (this.propsChangedDestroyCallbacks) {
971
+ this.propsChangedDestroyCallbacks.forEach(fn => {
972
+ fn();
973
+ });
974
+ }
975
+ if (this.unmountedCallbacks) {
976
+ this.unmountedCallbacks.forEach(fn => {
977
+ fn();
978
+ });
1144
979
  }
1145
980
  this.parentComponent =
1146
981
  this.propsChangedDestroyCallbacks =
@@ -1149,7 +984,6 @@ class Component {
1149
984
  this.updatedCallbacks =
1150
985
  this.propsChangedCallbacks =
1151
986
  this.unmountedCallbacks = null;
1152
- this.changedSubComponents.clear();
1153
987
  }
1154
988
  rendered() {
1155
989
  this.changedSubComponents.clear();
@@ -1162,7 +996,7 @@ class Component {
1162
996
  }
1163
997
  if (this.changed) {
1164
998
  Promise.resolve().then(() => {
1165
- if (this.parentComponent instanceof Component) {
999
+ if (this.parentComponent) {
1166
1000
  this.parentComponent.markAsChanged(this);
1167
1001
  }
1168
1002
  });
@@ -1303,11 +1137,20 @@ function withAnnotation(annotation, componentSetup) {
1303
1137
  return function (props) {
1304
1138
  const instance = getCurrentInstance();
1305
1139
  const parentInjector = injectMap.get(instance) || getInjector(instance.parentComponent);
1306
- const injector = new ReflectiveInjector(parentInjector, annotation.providers || [], annotation.scope);
1140
+ const injector = new ReflectiveInjector(parentInjector, [{
1141
+ provide: Injector,
1142
+ useFactory() {
1143
+ return injector;
1144
+ }
1145
+ }, ...(annotation.providers || [])], annotation.scope);
1307
1146
  injectMap.set(instance, injector);
1308
1147
  return componentSetup(props);
1309
1148
  };
1310
1149
  }
1150
+ /**
1151
+ * @deprecated
1152
+ * @param props
1153
+ */
1311
1154
  function Context(props) {
1312
1155
  function createContextComponent(providers) {
1313
1156
  return withAnnotation({
@@ -1342,11 +1185,89 @@ function withMemo(canUseMemo, render) {
1342
1185
  };
1343
1186
  }
1344
1187
 
1188
+ function hasChange(newProps, oldProps) {
1189
+ const newKeys = Object.keys(oldProps);
1190
+ const oldKeys = Object.keys(newProps);
1191
+ if (oldKeys.length !== newKeys.length) {
1192
+ return true;
1193
+ }
1194
+ const len = oldKeys.length;
1195
+ for (let i = 0; i < len; i++) {
1196
+ const key = newKeys[i];
1197
+ if (newProps[key] !== oldProps[key]) {
1198
+ return true;
1199
+ }
1200
+ }
1201
+ return false;
1202
+ }
1203
+ const refKey = 'ref';
1204
+ function comparePropsWithCallbacks(oldProps, newProps, onDeleted, onAdded, onUpdated) {
1205
+ for (const key in oldProps) {
1206
+ if (!(key in newProps)) {
1207
+ onDeleted(key, oldProps[key]);
1208
+ }
1209
+ }
1210
+ for (const key in newProps) {
1211
+ if (!(key in oldProps)) {
1212
+ onAdded(key, newProps[key]);
1213
+ }
1214
+ else if (oldProps[key] !== newProps[key]) {
1215
+ onUpdated(key, newProps[key], oldProps[key]);
1216
+ }
1217
+ }
1218
+ }
1219
+ function classToString(config) {
1220
+ if (typeof config === 'string') {
1221
+ return config;
1222
+ }
1223
+ if (!config) {
1224
+ return '';
1225
+ }
1226
+ if (Array.isArray(config)) {
1227
+ const classes = [];
1228
+ for (const i of config) {
1229
+ const v = classToString(i);
1230
+ if (v) {
1231
+ classes.push(v);
1232
+ }
1233
+ }
1234
+ return classes.join(' ');
1235
+ }
1236
+ if (typeof config === 'object') {
1237
+ if (config.toString !== Object.prototype.toString && !config.toString.toString().includes('[native code]')) {
1238
+ return config.toString();
1239
+ }
1240
+ const classes = [];
1241
+ for (const key in config) {
1242
+ if ({}.hasOwnProperty.call(config, key) && config[key]) {
1243
+ classes.push(key);
1244
+ }
1245
+ }
1246
+ return classes.join(' ');
1247
+ }
1248
+ return '';
1249
+ }
1250
+ function styleToObject(style) {
1251
+ if (typeof style !== 'string') {
1252
+ return style || {};
1253
+ }
1254
+ const obj = {};
1255
+ style.split(';').map(s => s.split(':')).forEach(v => {
1256
+ if (!v[0] || !v[1]) {
1257
+ return;
1258
+ }
1259
+ obj[v[0].trim()] = v[1].trim();
1260
+ });
1261
+ return obj;
1262
+ }
1263
+ const TextAtomType = Symbol('Text');
1264
+ const ElementAtomType = Symbol('Element');
1265
+ const ComponentAtomType = Symbol('Component');
1266
+
1345
1267
  const ElementNamespaceMap = {
1346
1268
  svg: 'svg',
1347
1269
  math: 'mathml',
1348
1270
  };
1349
- const componentViewCache = new WeakMap();
1350
1271
  const listenerReg = /^on[A-Z]/;
1351
1272
  function createRenderer(component, nativeRenderer, namespace) {
1352
1273
  let isInit = true;
@@ -1370,7 +1291,7 @@ function createRenderer(component, nativeRenderer, namespace) {
1370
1291
  });
1371
1292
  }
1372
1293
  else {
1373
- updateView(nativeRenderer, component, false);
1294
+ deepUpdateByComponentDirtyTree(nativeRenderer, component, false);
1374
1295
  }
1375
1296
  };
1376
1297
  }
@@ -1395,37 +1316,39 @@ function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1395
1316
  child = child.sibling;
1396
1317
  }
1397
1318
  }
1398
- function updateView(nativeRenderer, component, needMove) {
1319
+ function patchComponent(nativeRenderer, component, oldChildAtom, newAtom, context, needMove) {
1320
+ const newTemplate = component.rerender();
1321
+ newAtom.child = createChildChain(newTemplate, newAtom.namespace);
1322
+ diff(nativeRenderer, component, newAtom.child, oldChildAtom, context, needMove);
1323
+ }
1324
+ function deepUpdateByComponentDirtyTree(nativeRenderer, component, needMove) {
1399
1325
  if (component.dirty) {
1400
- const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1401
- applyChanges(nativeRenderer, component, atom, {
1402
- host,
1403
- isParent,
1404
- rootHost
1405
- }, needMove);
1326
+ const canUpdate = component.canUpdate(component.props, component.props);
1327
+ if (canUpdate) {
1328
+ const { atom, host, isParent, rootHost } = component.viewMetadata;
1329
+ const context = {
1330
+ host,
1331
+ isParent,
1332
+ rootHost
1333
+ };
1334
+ const diffAtom = atom.child;
1335
+ patchComponent(nativeRenderer, component, diffAtom, atom, context, needMove);
1336
+ const next = atom.sibling;
1337
+ if (next && next.jsxNode instanceof Component) {
1338
+ const view = next.jsxNode.viewMetadata;
1339
+ view.host = context.host;
1340
+ view.isParent = context.isParent;
1341
+ }
1342
+ }
1343
+ component.rendered();
1406
1344
  }
1407
1345
  else if (component.changed) {
1408
1346
  component.changedSubComponents.forEach(child => {
1409
- updateView(nativeRenderer, child, needMove);
1347
+ deepUpdateByComponentDirtyTree(nativeRenderer, child, needMove);
1410
1348
  });
1411
1349
  component.rendered();
1412
1350
  }
1413
1351
  }
1414
- function applyChanges(nativeRenderer, component, atom, context, needMove) {
1415
- const diffAtom = atom.child;
1416
- component.update(component.props, newTemplate => {
1417
- atom.child = createChildChain(newTemplate, atom.namespace);
1418
- diff(nativeRenderer, component, atom.child, diffAtom, context, needMove);
1419
- const next = atom.sibling;
1420
- if (next && next.jsxNode instanceof Component) {
1421
- const view = componentViewCache.get(next.jsxNode);
1422
- view.host = context.host;
1423
- view.isParent = context.isParent;
1424
- }
1425
- }, (skipSubComponentDiff) => {
1426
- reuseComponentView(nativeRenderer, atom, context, needMove, skipSubComponentDiff);
1427
- });
1428
- }
1429
1352
  function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1430
1353
  const commits = [];
1431
1354
  function changeOffset() {
@@ -1441,7 +1364,8 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1441
1364
  dirtyDiffAtom = dirtyDiffAtom.sibling;
1442
1365
  }
1443
1366
  let offset = 0;
1444
- for (let i = 0; i < commits.length; i++) {
1367
+ const len = commits.length;
1368
+ for (let i = 0; i < len; i++) {
1445
1369
  const commit = commits[i];
1446
1370
  while (oldAtom) {
1447
1371
  if (oldAtom.index <= i) {
@@ -1451,7 +1375,7 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1451
1375
  }
1452
1376
  break;
1453
1377
  }
1454
- commit(offset, needMove);
1378
+ commit.callback(commit.params, offset, needMove);
1455
1379
  }
1456
1380
  }
1457
1381
  function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, parentComponent, effect) {
@@ -1460,17 +1384,19 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1460
1384
  while (oldAtom) {
1461
1385
  const newAtomType = newAtom.type;
1462
1386
  if (oldAtom.type === newAtomType && oldAtom.nodeType === newAtom.nodeType && oldAtom.key === newAtom.key) {
1463
- let commit;
1464
- if (newAtomType === TextAtomType) {
1465
- commit = updateText(newAtom, oldAtom, nativeRenderer, context);
1466
- }
1467
- else if (newAtomType === ComponentAtomType) {
1468
- commit = updateComponent(newAtom, oldAtom, nativeRenderer, context);
1469
- }
1470
- else {
1471
- commit = updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent);
1472
- }
1473
- commits.push(commit);
1387
+ commits.push({
1388
+ callback: newAtomType === TextAtomType ? updateText :
1389
+ newAtomType === ComponentAtomType ? updateComponent :
1390
+ updateElement,
1391
+ params: {
1392
+ oldAtom,
1393
+ newAtom,
1394
+ nativeRenderer,
1395
+ context,
1396
+ effect,
1397
+ parentComponent
1398
+ }
1399
+ });
1474
1400
  const next = oldAtom.sibling;
1475
1401
  if (!prev) {
1476
1402
  return next;
@@ -1481,81 +1407,84 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1481
1407
  prev = oldAtom;
1482
1408
  oldAtom = oldAtom.sibling;
1483
1409
  }
1484
- commits.push(createNewView(newAtom, nativeRenderer, context, parentComponent, effect));
1410
+ commits.push({
1411
+ callback: patchUpdate,
1412
+ params: {
1413
+ oldAtom: oldAtom,
1414
+ newAtom,
1415
+ nativeRenderer,
1416
+ context,
1417
+ effect,
1418
+ parentComponent
1419
+ }
1420
+ });
1485
1421
  return startDiffAtom;
1486
1422
  }
1487
- function createNewView(start, nativeRenderer, context, parentComponent, effect) {
1488
- return function () {
1489
- buildView(nativeRenderer, parentComponent, start, context);
1490
- effect();
1491
- };
1423
+ function patchUpdate(params) {
1424
+ const { nativeRenderer, parentComponent, newAtom, context, effect } = params;
1425
+ buildView(nativeRenderer, parentComponent, newAtom, context);
1426
+ effect();
1492
1427
  }
1493
- function updateText(newAtom, oldAtom, nativeRenderer, context) {
1494
- return function (offset, needMove) {
1495
- const nativeNode = oldAtom.nativeNode;
1496
- newAtom.nativeNode = nativeNode;
1497
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1498
- insertNode(nativeRenderer, newAtom, context);
1499
- }
1500
- context.host = nativeNode;
1501
- context.isParent = false;
1502
- };
1428
+ function updateText(params, offset, needMove) {
1429
+ const { oldAtom, newAtom, nativeRenderer, context } = params;
1430
+ const nativeNode = oldAtom.nativeNode;
1431
+ newAtom.nativeNode = nativeNode;
1432
+ if (needMove || newAtom.index - offset !== oldAtom.index) {
1433
+ insertNode(nativeRenderer, newAtom, context);
1434
+ }
1435
+ context.host = nativeNode;
1436
+ context.isParent = false;
1503
1437
  }
1504
- function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent) {
1505
- return function (offset, needMove) {
1506
- newAtom.nativeNode = oldAtom.nativeNode;
1507
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1508
- insertNode(nativeRenderer, newAtom, context);
1509
- }
1510
- context.host = newAtom.nativeNode;
1511
- context.isParent = false;
1512
- updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1513
- host: newAtom.nativeNode,
1514
- isParent: true,
1515
- rootHost: context.rootHost
1516
- });
1517
- };
1438
+ function updateElement(params, offset, needMove) {
1439
+ const { nativeRenderer, newAtom, oldAtom, context, parentComponent } = params;
1440
+ newAtom.nativeNode = oldAtom.nativeNode;
1441
+ if (needMove || newAtom.index - offset !== oldAtom.index) {
1442
+ insertNode(nativeRenderer, newAtom, context);
1443
+ }
1444
+ context.host = newAtom.nativeNode;
1445
+ context.isParent = false;
1446
+ updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1447
+ host: newAtom.nativeNode,
1448
+ isParent: true,
1449
+ rootHost: context.rootHost
1450
+ });
1518
1451
  }
1519
- function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1520
- return function (offset, needMove) {
1521
- const component = reusedAtom.jsxNode;
1522
- const newProps = newAtom.jsxNode.props;
1523
- const portalHost = component.instance.$portalHost;
1524
- context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1525
- componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1526
- newAtom.jsxNode = component;
1527
- component.update(newProps, newTemplate => {
1528
- if (newTemplate) {
1529
- newAtom.child = createChildChain(newTemplate, newAtom.namespace);
1530
- }
1531
- if (newAtom.child) {
1532
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1533
- }
1534
- else if (reusedAtom.child) {
1535
- let atom = reusedAtom.child;
1536
- while (atom) {
1537
- cleanView(nativeRenderer, atom, true);
1538
- atom = atom.sibling;
1539
- }
1540
- }
1541
- }, (skipSubComponentDiff) => {
1542
- newAtom.child = reusedAtom.child;
1543
- reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index, skipSubComponentDiff);
1544
- });
1545
- };
1452
+ function updateComponent(params, offset, needMove) {
1453
+ const { oldAtom, newAtom, nativeRenderer } = params;
1454
+ let context = params.context;
1455
+ const component = oldAtom.jsxNode;
1456
+ const portalHost = component.instance.$portalHost;
1457
+ context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1458
+ component.viewMetadata = Object.assign({ atom: newAtom }, context);
1459
+ const newProps = newAtom.jsxNode.props;
1460
+ newAtom.jsxNode = component;
1461
+ needMove = needMove || newAtom.index - offset !== oldAtom.index;
1462
+ const canUpdate = component.canUpdate(component.props, newProps);
1463
+ const propsIsChanged = hasChange(newProps, component.props);
1464
+ if (propsIsChanged) {
1465
+ component.updateProps(newProps);
1466
+ }
1467
+ if (canUpdate && (propsIsChanged || component.dirty)) {
1468
+ patchComponent(nativeRenderer, component, oldAtom.child, newAtom, context, needMove);
1469
+ const next = oldAtom.sibling;
1470
+ if (next && next.jsxNode instanceof Component) {
1471
+ const view = next.jsxNode.viewMetadata;
1472
+ view.host = context.host;
1473
+ view.isParent = context.isParent;
1474
+ }
1475
+ }
1476
+ else {
1477
+ newAtom.child = oldAtom.child;
1478
+ reuseComponentView(nativeRenderer, newAtom.child, context, needMove, true);
1479
+ }
1480
+ component.rendered();
1546
1481
  }
1547
1482
  function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1548
1483
  const updateContext = (atom) => {
1549
1484
  if (atom.jsxNode instanceof Component) {
1550
- if (skipSubComponentDiff || !moveView) {
1551
- let child = atom.child;
1552
- while (child) {
1553
- updateContext(child);
1554
- child = child.sibling;
1555
- }
1556
- }
1557
- else {
1558
- applyChanges(nativeRenderer, atom.jsxNode, atom, context, true);
1485
+ reuseComponentView(nativeRenderer, atom.child, context, moveView, skipSubComponentDiff);
1486
+ if (!skipSubComponentDiff) {
1487
+ deepUpdateByComponentDirtyTree(nativeRenderer, atom.jsxNode, moveView);
1559
1488
  }
1560
1489
  }
1561
1490
  else {
@@ -1576,7 +1505,7 @@ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponen
1576
1505
  let child = atom.child;
1577
1506
  while (child) {
1578
1507
  if (child.jsxNode instanceof Component) {
1579
- updateView(nativeRenderer, child.jsxNode, false);
1508
+ deepUpdateByComponentDirtyTree(nativeRenderer, child.jsxNode, false);
1580
1509
  }
1581
1510
  else {
1582
1511
  reuseElementChildrenView(nativeRenderer, child);
@@ -1623,7 +1552,7 @@ function componentRender(nativeRenderer, component, from, context) {
1623
1552
  component.render((template, portalHost) => {
1624
1553
  from.child = createChildChain(template, from.namespace);
1625
1554
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1626
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1555
+ component.viewMetadata = Object.assign({ atom: from }, context);
1627
1556
  let child = from.child;
1628
1557
  while (child) {
1629
1558
  buildView(nativeRenderer, component, child, context);
@@ -1648,14 +1577,14 @@ function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, namespace, key)
1648
1577
  }
1649
1578
  function createChainByNode(jsxNode, prevAtom, elementNamespace) {
1650
1579
  const type = typeof jsxNode;
1651
- if (jsxNode !== null && type !== 'undefined' && type !== 'boolean') {
1652
- if (typeof jsxNode === 'string') {
1580
+ if (jsxNode != null && type !== 'boolean') {
1581
+ if (type === 'string') {
1653
1582
  return createChainByJSXNode(TextAtomType, jsxNode, jsxNode, prevAtom, elementNamespace);
1654
1583
  }
1655
- if (Array.isArray(jsxNode)) {
1656
- return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1657
- }
1658
1584
  if (type === 'object') {
1585
+ if (Array.isArray(jsxNode)) {
1586
+ return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1587
+ }
1659
1588
  const nodeType = typeof jsxNode.type;
1660
1589
  if (nodeType === 'string') {
1661
1590
  return createChainByJSXNode(ElementAtomType, jsxNode, jsxNode.type, prevAtom, elementNamespace || ElementNamespaceMap[jsxNode.type], jsxNode.key);
@@ -1766,43 +1695,66 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1766
1695
  reuseElementChildrenView(nativeRenderer, newAtom);
1767
1696
  return;
1768
1697
  }
1769
- const changes = getObjectChanges(newVNode.props, oldVNode.props);
1770
1698
  let unBindRefs;
1771
1699
  let bindRefs;
1772
1700
  let updatedChildren = false;
1773
- let len = changes.remove.length;
1774
- for (let i = 0; i < len; i++) {
1775
- const [key, value] = changes.remove[i];
1701
+ comparePropsWithCallbacks(oldVNode.props, newVNode.props, (key, oldValue) => {
1776
1702
  if (key === 'children') {
1777
1703
  updatedChildren = true;
1778
1704
  cleanElementChildren(oldAtom, nativeRenderer);
1779
- continue;
1705
+ return;
1780
1706
  }
1781
1707
  if (key === 'class') {
1782
1708
  nativeRenderer.setClass(nativeNode, '', isSvg);
1783
- continue;
1709
+ return;
1784
1710
  }
1785
1711
  if (key === 'style') {
1786
- for (const styleName in styleToObject(value)) {
1712
+ for (const styleName in styleToObject(oldValue)) {
1787
1713
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1788
1714
  }
1789
- continue;
1715
+ return;
1790
1716
  }
1791
1717
  if (listenerReg.test(key)) {
1792
- if (typeof value === 'function') {
1793
- nativeRenderer.unListen(nativeNode, key, value, isSvg);
1718
+ if (typeof oldValue === 'function') {
1719
+ nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1794
1720
  }
1795
- continue;
1721
+ return;
1796
1722
  }
1797
1723
  if (key === refKey) {
1798
- unBindRefs = value;
1799
- continue;
1724
+ unBindRefs = oldValue;
1725
+ return;
1800
1726
  }
1801
1727
  nativeRenderer.removeProperty(nativeNode, key, isSvg);
1802
- }
1803
- len = changes.replace.length;
1804
- for (let i = 0; i < len; i++) {
1805
- const [key, newValue, oldValue] = changes.replace[i];
1728
+ }, (key, value) => {
1729
+ if (key === 'children') {
1730
+ updatedChildren = true;
1731
+ newAtom.child = createElementChildren(newVNode.type, value, isSvg);
1732
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1733
+ return;
1734
+ }
1735
+ if (key === 'class') {
1736
+ nativeRenderer.setClass(nativeNode, classToString(value), isSvg);
1737
+ return;
1738
+ }
1739
+ if (key === 'style') {
1740
+ const styleObj = styleToObject(value);
1741
+ for (const styleName in styleObj) {
1742
+ nativeRenderer.setStyle(nativeNode, styleName, styleObj[styleName], isSvg);
1743
+ }
1744
+ return;
1745
+ }
1746
+ if (listenerReg.test(key)) {
1747
+ if (typeof value === 'function') {
1748
+ nativeRenderer.listen(nativeNode, key, value, isSvg);
1749
+ }
1750
+ return;
1751
+ }
1752
+ if (key === refKey) {
1753
+ bindRefs = value;
1754
+ return;
1755
+ }
1756
+ nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1757
+ }, (key, newValue, oldValue) => {
1806
1758
  if (key === 'children') {
1807
1759
  updatedChildren = true;
1808
1760
  newAtom.child = createElementChildren(newVNode.type, newValue, isSvg);
@@ -1815,7 +1767,7 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1815
1767
  else {
1816
1768
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1817
1769
  }
1818
- continue;
1770
+ return;
1819
1771
  }
1820
1772
  if (key === 'class') {
1821
1773
  const oldClassName = classToString(oldValue);
@@ -1823,62 +1775,30 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1823
1775
  if (oldClassName !== newClassName) {
1824
1776
  nativeRenderer.setClass(nativeNode, newClassName, isSvg);
1825
1777
  }
1826
- continue;
1778
+ return;
1827
1779
  }
1828
1780
  if (key === 'style') {
1829
- const styleChanges = getObjectChanges(styleToObject(newValue) || {}, styleToObject(oldValue) || {});
1830
- for (const [styleName] of styleChanges.remove) {
1781
+ comparePropsWithCallbacks(styleToObject(oldValue), styleToObject(newValue), styleName => {
1831
1782
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1832
- }
1833
- for (const [styleName, styleValue] of [...styleChanges.add, ...styleChanges.replace]) {
1783
+ }, (styleName, styleValue) => {
1834
1784
  nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1835
- }
1836
- continue;
1785
+ }, (styleName, styleValue) => {
1786
+ nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1787
+ });
1788
+ return;
1837
1789
  }
1838
1790
  if (listenerReg.test(key)) {
1839
1791
  nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1840
1792
  nativeRenderer.listen(nativeNode, key, newValue, isSvg);
1841
- continue;
1793
+ return;
1842
1794
  }
1843
1795
  if (key === refKey) {
1844
1796
  unBindRefs = oldValue;
1845
1797
  bindRefs = newValue;
1846
- continue;
1798
+ return;
1847
1799
  }
1848
1800
  nativeRenderer.setProperty(nativeNode, key, newValue, isSvg);
1849
- }
1850
- len = changes.add.length;
1851
- for (let i = 0; i < len; i++) {
1852
- const [key, value] = changes.add[i];
1853
- if (key === 'children') {
1854
- updatedChildren = true;
1855
- newAtom.child = createElementChildren(newVNode.type, value, isSvg);
1856
- buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1857
- continue;
1858
- }
1859
- if (key === 'class') {
1860
- nativeRenderer.setClass(nativeNode, classToString(value), isSvg);
1861
- continue;
1862
- }
1863
- if (key === 'style') {
1864
- const styleObj = styleToObject(value);
1865
- for (const styleName in styleObj) {
1866
- nativeRenderer.setStyle(nativeNode, styleName, styleObj[styleName], isSvg);
1867
- }
1868
- continue;
1869
- }
1870
- if (listenerReg.test(key)) {
1871
- if (typeof value === 'function') {
1872
- nativeRenderer.listen(nativeNode, key, value, isSvg);
1873
- }
1874
- continue;
1875
- }
1876
- if (key === refKey) {
1877
- bindRefs = value;
1878
- continue;
1879
- }
1880
- nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1881
- }
1801
+ });
1882
1802
  if (!updatedChildren) {
1883
1803
  newAtom.child = oldAtom.child;
1884
1804
  reuseElementChildrenView(nativeRenderer, newAtom);