@viewfly/core 1.2.2 → 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.
@@ -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,84 @@ 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, true);
1477
+ }
1478
+ component.rendered();
1553
1479
  }
1554
1480
  function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1555
1481
  const updateContext = (atom) => {
1556
1482
  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);
1483
+ reuseComponentView(nativeRenderer, atom.child, context, moveView, skipSubComponentDiff);
1484
+ if (!skipSubComponentDiff) {
1485
+ deepUpdateByComponentDirtyTree(nativeRenderer, atom.jsxNode, moveView);
1566
1486
  }
1567
1487
  }
1568
1488
  else {
@@ -1583,7 +1503,7 @@ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponen
1583
1503
  let child = atom.child;
1584
1504
  while (child) {
1585
1505
  if (child.jsxNode instanceof Component) {
1586
- updateView(nativeRenderer, child.jsxNode, false);
1506
+ deepUpdateByComponentDirtyTree(nativeRenderer, child.jsxNode, false);
1587
1507
  }
1588
1508
  else {
1589
1509
  reuseElementChildrenView(nativeRenderer, child);
@@ -1630,7 +1550,7 @@ function componentRender(nativeRenderer, component, from, context) {
1630
1550
  component.render((template, portalHost) => {
1631
1551
  from.child = createChildChain(template, from.namespace);
1632
1552
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1633
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1553
+ component.viewMetadata = Object.assign({ atom: from }, context);
1634
1554
  let child = from.child;
1635
1555
  while (child) {
1636
1556
  buildView(nativeRenderer, component, child, context);
@@ -1655,14 +1575,14 @@ function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, namespace, key)
1655
1575
  }
1656
1576
  function createChainByNode(jsxNode, prevAtom, elementNamespace) {
1657
1577
  const type = typeof jsxNode;
1658
- if (jsxNode !== null && type !== 'undefined' && type !== 'boolean') {
1659
- if (typeof jsxNode === 'string') {
1578
+ if (jsxNode != null && type !== 'boolean') {
1579
+ if (type === 'string') {
1660
1580
  return createChainByJSXNode(TextAtomType, jsxNode, jsxNode, prevAtom, elementNamespace);
1661
1581
  }
1662
- if (Array.isArray(jsxNode)) {
1663
- return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1664
- }
1665
1582
  if (type === 'object') {
1583
+ if (Array.isArray(jsxNode)) {
1584
+ return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1585
+ }
1666
1586
  const nodeType = typeof jsxNode.type;
1667
1587
  if (nodeType === 'string') {
1668
1588
  return createChainByJSXNode(ElementAtomType, jsxNode, jsxNode.type, prevAtom, elementNamespace || ElementNamespaceMap[jsxNode.type], jsxNode.key);
@@ -1773,43 +1693,66 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1773
1693
  reuseElementChildrenView(nativeRenderer, newAtom);
1774
1694
  return;
1775
1695
  }
1776
- const changes = getObjectChanges(newVNode.props, oldVNode.props);
1777
1696
  let unBindRefs;
1778
1697
  let bindRefs;
1779
1698
  let updatedChildren = false;
1780
- let len = changes.remove.length;
1781
- for (let i = 0; i < len; i++) {
1782
- const [key, value] = changes.remove[i];
1699
+ comparePropsWithCallbacks(oldVNode.props, newVNode.props, (key, oldValue) => {
1783
1700
  if (key === 'children') {
1784
1701
  updatedChildren = true;
1785
1702
  cleanElementChildren(oldAtom, nativeRenderer);
1786
- continue;
1703
+ return;
1787
1704
  }
1788
1705
  if (key === 'class') {
1789
1706
  nativeRenderer.setClass(nativeNode, '', isSvg);
1790
- continue;
1707
+ return;
1791
1708
  }
1792
1709
  if (key === 'style') {
1793
- for (const styleName in styleToObject(value)) {
1710
+ for (const styleName in styleToObject(oldValue)) {
1794
1711
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1795
1712
  }
1796
- continue;
1713
+ return;
1797
1714
  }
1798
1715
  if (listenerReg.test(key)) {
1799
- if (typeof value === 'function') {
1800
- nativeRenderer.unListen(nativeNode, key, value, isSvg);
1716
+ if (typeof oldValue === 'function') {
1717
+ nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1801
1718
  }
1802
- continue;
1719
+ return;
1803
1720
  }
1804
1721
  if (key === refKey) {
1805
- unBindRefs = value;
1806
- continue;
1722
+ unBindRefs = oldValue;
1723
+ return;
1807
1724
  }
1808
1725
  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];
1726
+ }, (key, value) => {
1727
+ if (key === 'children') {
1728
+ updatedChildren = true;
1729
+ newAtom.child = createElementChildren(newVNode.type, value, isSvg);
1730
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1731
+ return;
1732
+ }
1733
+ if (key === 'class') {
1734
+ nativeRenderer.setClass(nativeNode, classToString(value), isSvg);
1735
+ return;
1736
+ }
1737
+ if (key === 'style') {
1738
+ const styleObj = styleToObject(value);
1739
+ for (const styleName in styleObj) {
1740
+ nativeRenderer.setStyle(nativeNode, styleName, styleObj[styleName], isSvg);
1741
+ }
1742
+ return;
1743
+ }
1744
+ if (listenerReg.test(key)) {
1745
+ if (typeof value === 'function') {
1746
+ nativeRenderer.listen(nativeNode, key, value, isSvg);
1747
+ }
1748
+ return;
1749
+ }
1750
+ if (key === refKey) {
1751
+ bindRefs = value;
1752
+ return;
1753
+ }
1754
+ nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1755
+ }, (key, newValue, oldValue) => {
1813
1756
  if (key === 'children') {
1814
1757
  updatedChildren = true;
1815
1758
  newAtom.child = createElementChildren(newVNode.type, newValue, isSvg);
@@ -1822,7 +1765,7 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1822
1765
  else {
1823
1766
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1824
1767
  }
1825
- continue;
1768
+ return;
1826
1769
  }
1827
1770
  if (key === 'class') {
1828
1771
  const oldClassName = classToString(oldValue);
@@ -1830,62 +1773,30 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1830
1773
  if (oldClassName !== newClassName) {
1831
1774
  nativeRenderer.setClass(nativeNode, newClassName, isSvg);
1832
1775
  }
1833
- continue;
1776
+ return;
1834
1777
  }
1835
1778
  if (key === 'style') {
1836
- const styleChanges = getObjectChanges(styleToObject(newValue) || {}, styleToObject(oldValue) || {});
1837
- for (const [styleName] of styleChanges.remove) {
1779
+ comparePropsWithCallbacks(styleToObject(oldValue), styleToObject(newValue), styleName => {
1838
1780
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1839
- }
1840
- for (const [styleName, styleValue] of [...styleChanges.add, ...styleChanges.replace]) {
1781
+ }, (styleName, styleValue) => {
1841
1782
  nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1842
- }
1843
- continue;
1783
+ }, (styleName, styleValue) => {
1784
+ nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1785
+ });
1786
+ return;
1844
1787
  }
1845
1788
  if (listenerReg.test(key)) {
1846
1789
  nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1847
1790
  nativeRenderer.listen(nativeNode, key, newValue, isSvg);
1848
- continue;
1791
+ return;
1849
1792
  }
1850
1793
  if (key === refKey) {
1851
1794
  unBindRefs = oldValue;
1852
1795
  bindRefs = newValue;
1853
- continue;
1796
+ return;
1854
1797
  }
1855
1798
  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
- }
1799
+ });
1889
1800
  if (!updatedChildren) {
1890
1801
  newAtom.child = oldAtom.child;
1891
1802
  reuseElementChildrenView(nativeRenderer, newAtom);