@viewfly/core 1.2.2 → 1.2.5

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