@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.
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
  });
@@ -1351,11 +1185,89 @@ function withMemo(canUseMemo, render) {
1351
1185
  };
1352
1186
  }
1353
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
+
1354
1267
  const ElementNamespaceMap = {
1355
1268
  svg: 'svg',
1356
1269
  math: 'mathml',
1357
1270
  };
1358
- const componentViewCache = new WeakMap();
1359
1271
  const listenerReg = /^on[A-Z]/;
1360
1272
  function createRenderer(component, nativeRenderer, namespace) {
1361
1273
  let isInit = true;
@@ -1379,7 +1291,7 @@ function createRenderer(component, nativeRenderer, namespace) {
1379
1291
  });
1380
1292
  }
1381
1293
  else {
1382
- updateView(nativeRenderer, component, false);
1294
+ deepUpdateByComponentDirtyTree(nativeRenderer, component, false);
1383
1295
  }
1384
1296
  };
1385
1297
  }
@@ -1404,37 +1316,39 @@ function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1404
1316
  child = child.sibling;
1405
1317
  }
1406
1318
  }
1407
- 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) {
1408
1325
  if (component.dirty) {
1409
- const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1410
- applyChanges(nativeRenderer, component, atom, {
1411
- host,
1412
- isParent,
1413
- rootHost
1414
- }, 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();
1415
1344
  }
1416
1345
  else if (component.changed) {
1417
1346
  component.changedSubComponents.forEach(child => {
1418
- updateView(nativeRenderer, child, needMove);
1347
+ deepUpdateByComponentDirtyTree(nativeRenderer, child, needMove);
1419
1348
  });
1420
1349
  component.rendered();
1421
1350
  }
1422
1351
  }
1423
- function applyChanges(nativeRenderer, component, atom, context, needMove) {
1424
- const diffAtom = atom.child;
1425
- component.update(component.props, newTemplate => {
1426
- atom.child = createChildChain(newTemplate, atom.namespace);
1427
- diff(nativeRenderer, component, atom.child, diffAtom, context, needMove);
1428
- const next = atom.sibling;
1429
- if (next && next.jsxNode instanceof Component) {
1430
- const view = componentViewCache.get(next.jsxNode);
1431
- view.host = context.host;
1432
- view.isParent = context.isParent;
1433
- }
1434
- }, (skipSubComponentDiff) => {
1435
- reuseComponentView(nativeRenderer, atom, context, needMove, skipSubComponentDiff);
1436
- });
1437
- }
1438
1352
  function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1439
1353
  const commits = [];
1440
1354
  function changeOffset() {
@@ -1450,7 +1364,8 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1450
1364
  dirtyDiffAtom = dirtyDiffAtom.sibling;
1451
1365
  }
1452
1366
  let offset = 0;
1453
- for (let i = 0; i < commits.length; i++) {
1367
+ const len = commits.length;
1368
+ for (let i = 0; i < len; i++) {
1454
1369
  const commit = commits[i];
1455
1370
  while (oldAtom) {
1456
1371
  if (oldAtom.index <= i) {
@@ -1460,7 +1375,7 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1460
1375
  }
1461
1376
  break;
1462
1377
  }
1463
- commit(offset, needMove);
1378
+ commit.callback(commit.params, offset, needMove);
1464
1379
  }
1465
1380
  }
1466
1381
  function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, parentComponent, effect) {
@@ -1469,17 +1384,19 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1469
1384
  while (oldAtom) {
1470
1385
  const newAtomType = newAtom.type;
1471
1386
  if (oldAtom.type === newAtomType && oldAtom.nodeType === newAtom.nodeType && oldAtom.key === newAtom.key) {
1472
- let commit;
1473
- if (newAtomType === TextAtomType) {
1474
- commit = updateText(newAtom, oldAtom, nativeRenderer, context);
1475
- }
1476
- else if (newAtomType === ComponentAtomType) {
1477
- commit = updateComponent(newAtom, oldAtom, nativeRenderer, context);
1478
- }
1479
- else {
1480
- commit = updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent);
1481
- }
1482
- 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
+ });
1483
1400
  const next = oldAtom.sibling;
1484
1401
  if (!prev) {
1485
1402
  return next;
@@ -1490,81 +1407,84 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1490
1407
  prev = oldAtom;
1491
1408
  oldAtom = oldAtom.sibling;
1492
1409
  }
1493
- 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
+ });
1494
1421
  return startDiffAtom;
1495
1422
  }
1496
- function createNewView(start, nativeRenderer, context, parentComponent, effect) {
1497
- return function () {
1498
- buildView(nativeRenderer, parentComponent, start, context);
1499
- effect();
1500
- };
1423
+ function patchUpdate(params) {
1424
+ const { nativeRenderer, parentComponent, newAtom, context, effect } = params;
1425
+ buildView(nativeRenderer, parentComponent, newAtom, context);
1426
+ effect();
1501
1427
  }
1502
- function updateText(newAtom, oldAtom, nativeRenderer, context) {
1503
- return function (offset, needMove) {
1504
- const nativeNode = oldAtom.nativeNode;
1505
- newAtom.nativeNode = nativeNode;
1506
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1507
- insertNode(nativeRenderer, newAtom, context);
1508
- }
1509
- context.host = nativeNode;
1510
- context.isParent = false;
1511
- };
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;
1512
1437
  }
1513
- function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent) {
1514
- return function (offset, needMove) {
1515
- newAtom.nativeNode = oldAtom.nativeNode;
1516
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1517
- insertNode(nativeRenderer, newAtom, context);
1518
- }
1519
- context.host = newAtom.nativeNode;
1520
- context.isParent = false;
1521
- updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1522
- host: newAtom.nativeNode,
1523
- isParent: true,
1524
- rootHost: context.rootHost
1525
- });
1526
- };
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
+ });
1527
1451
  }
1528
- function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1529
- return function (offset, needMove) {
1530
- const component = reusedAtom.jsxNode;
1531
- const newProps = newAtom.jsxNode.props;
1532
- const portalHost = component.instance.$portalHost;
1533
- context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1534
- componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1535
- newAtom.jsxNode = component;
1536
- component.update(newProps, newTemplate => {
1537
- if (newTemplate) {
1538
- newAtom.child = createChildChain(newTemplate, newAtom.namespace);
1539
- }
1540
- if (newAtom.child) {
1541
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1542
- }
1543
- else if (reusedAtom.child) {
1544
- let atom = reusedAtom.child;
1545
- while (atom) {
1546
- cleanView(nativeRenderer, atom, true);
1547
- atom = atom.sibling;
1548
- }
1549
- }
1550
- }, (skipSubComponentDiff) => {
1551
- newAtom.child = reusedAtom.child;
1552
- reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index, skipSubComponentDiff);
1553
- });
1554
- };
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();
1555
1481
  }
1556
1482
  function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1557
1483
  const updateContext = (atom) => {
1558
1484
  if (atom.jsxNode instanceof Component) {
1559
- if (skipSubComponentDiff || !moveView) {
1560
- let child = atom.child;
1561
- while (child) {
1562
- updateContext(child);
1563
- child = child.sibling;
1564
- }
1565
- }
1566
- else {
1567
- applyChanges(nativeRenderer, atom.jsxNode, atom, context, true);
1485
+ reuseComponentView(nativeRenderer, atom.child, context, moveView, skipSubComponentDiff);
1486
+ if (!skipSubComponentDiff) {
1487
+ deepUpdateByComponentDirtyTree(nativeRenderer, atom.jsxNode, moveView);
1568
1488
  }
1569
1489
  }
1570
1490
  else {
@@ -1585,7 +1505,7 @@ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponen
1585
1505
  let child = atom.child;
1586
1506
  while (child) {
1587
1507
  if (child.jsxNode instanceof Component) {
1588
- updateView(nativeRenderer, child.jsxNode, false);
1508
+ deepUpdateByComponentDirtyTree(nativeRenderer, child.jsxNode, false);
1589
1509
  }
1590
1510
  else {
1591
1511
  reuseElementChildrenView(nativeRenderer, child);
@@ -1632,7 +1552,7 @@ function componentRender(nativeRenderer, component, from, context) {
1632
1552
  component.render((template, portalHost) => {
1633
1553
  from.child = createChildChain(template, from.namespace);
1634
1554
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1635
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1555
+ component.viewMetadata = Object.assign({ atom: from }, context);
1636
1556
  let child = from.child;
1637
1557
  while (child) {
1638
1558
  buildView(nativeRenderer, component, child, context);
@@ -1657,14 +1577,14 @@ function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, namespace, key)
1657
1577
  }
1658
1578
  function createChainByNode(jsxNode, prevAtom, elementNamespace) {
1659
1579
  const type = typeof jsxNode;
1660
- if (jsxNode !== null && type !== 'undefined' && type !== 'boolean') {
1661
- if (typeof jsxNode === 'string') {
1580
+ if (jsxNode != null && type !== 'boolean') {
1581
+ if (type === 'string') {
1662
1582
  return createChainByJSXNode(TextAtomType, jsxNode, jsxNode, prevAtom, elementNamespace);
1663
1583
  }
1664
- if (Array.isArray(jsxNode)) {
1665
- return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1666
- }
1667
1584
  if (type === 'object') {
1585
+ if (Array.isArray(jsxNode)) {
1586
+ return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1587
+ }
1668
1588
  const nodeType = typeof jsxNode.type;
1669
1589
  if (nodeType === 'string') {
1670
1590
  return createChainByJSXNode(ElementAtomType, jsxNode, jsxNode.type, prevAtom, elementNamespace || ElementNamespaceMap[jsxNode.type], jsxNode.key);
@@ -1775,43 +1695,66 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1775
1695
  reuseElementChildrenView(nativeRenderer, newAtom);
1776
1696
  return;
1777
1697
  }
1778
- const changes = getObjectChanges(newVNode.props, oldVNode.props);
1779
1698
  let unBindRefs;
1780
1699
  let bindRefs;
1781
1700
  let updatedChildren = false;
1782
- let len = changes.remove.length;
1783
- for (let i = 0; i < len; i++) {
1784
- const [key, value] = changes.remove[i];
1701
+ comparePropsWithCallbacks(oldVNode.props, newVNode.props, (key, oldValue) => {
1785
1702
  if (key === 'children') {
1786
1703
  updatedChildren = true;
1787
1704
  cleanElementChildren(oldAtom, nativeRenderer);
1788
- continue;
1705
+ return;
1789
1706
  }
1790
1707
  if (key === 'class') {
1791
1708
  nativeRenderer.setClass(nativeNode, '', isSvg);
1792
- continue;
1709
+ return;
1793
1710
  }
1794
1711
  if (key === 'style') {
1795
- for (const styleName in styleToObject(value)) {
1712
+ for (const styleName in styleToObject(oldValue)) {
1796
1713
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1797
1714
  }
1798
- continue;
1715
+ return;
1799
1716
  }
1800
1717
  if (listenerReg.test(key)) {
1801
- if (typeof value === 'function') {
1802
- nativeRenderer.unListen(nativeNode, key, value, isSvg);
1718
+ if (typeof oldValue === 'function') {
1719
+ nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1803
1720
  }
1804
- continue;
1721
+ return;
1805
1722
  }
1806
1723
  if (key === refKey) {
1807
- unBindRefs = value;
1808
- continue;
1724
+ unBindRefs = oldValue;
1725
+ return;
1809
1726
  }
1810
1727
  nativeRenderer.removeProperty(nativeNode, key, isSvg);
1811
- }
1812
- len = changes.replace.length;
1813
- for (let i = 0; i < len; i++) {
1814
- 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) => {
1815
1758
  if (key === 'children') {
1816
1759
  updatedChildren = true;
1817
1760
  newAtom.child = createElementChildren(newVNode.type, newValue, isSvg);
@@ -1824,7 +1767,7 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1824
1767
  else {
1825
1768
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1826
1769
  }
1827
- continue;
1770
+ return;
1828
1771
  }
1829
1772
  if (key === 'class') {
1830
1773
  const oldClassName = classToString(oldValue);
@@ -1832,62 +1775,30 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1832
1775
  if (oldClassName !== newClassName) {
1833
1776
  nativeRenderer.setClass(nativeNode, newClassName, isSvg);
1834
1777
  }
1835
- continue;
1778
+ return;
1836
1779
  }
1837
1780
  if (key === 'style') {
1838
- const styleChanges = getObjectChanges(styleToObject(newValue) || {}, styleToObject(oldValue) || {});
1839
- for (const [styleName] of styleChanges.remove) {
1781
+ comparePropsWithCallbacks(styleToObject(oldValue), styleToObject(newValue), styleName => {
1840
1782
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1841
- }
1842
- for (const [styleName, styleValue] of [...styleChanges.add, ...styleChanges.replace]) {
1783
+ }, (styleName, styleValue) => {
1843
1784
  nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1844
- }
1845
- continue;
1785
+ }, (styleName, styleValue) => {
1786
+ nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1787
+ });
1788
+ return;
1846
1789
  }
1847
1790
  if (listenerReg.test(key)) {
1848
1791
  nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1849
1792
  nativeRenderer.listen(nativeNode, key, newValue, isSvg);
1850
- continue;
1793
+ return;
1851
1794
  }
1852
1795
  if (key === refKey) {
1853
1796
  unBindRefs = oldValue;
1854
1797
  bindRefs = newValue;
1855
- continue;
1798
+ return;
1856
1799
  }
1857
1800
  nativeRenderer.setProperty(nativeNode, key, newValue, isSvg);
1858
- }
1859
- len = changes.add.length;
1860
- for (let i = 0; i < len; i++) {
1861
- const [key, value] = changes.add[i];
1862
- if (key === 'children') {
1863
- updatedChildren = true;
1864
- newAtom.child = createElementChildren(newVNode.type, value, isSvg);
1865
- buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1866
- continue;
1867
- }
1868
- if (key === 'class') {
1869
- nativeRenderer.setClass(nativeNode, classToString(value), isSvg);
1870
- continue;
1871
- }
1872
- if (key === 'style') {
1873
- const styleObj = styleToObject(value);
1874
- for (const styleName in styleObj) {
1875
- nativeRenderer.setStyle(nativeNode, styleName, styleObj[styleName], isSvg);
1876
- }
1877
- continue;
1878
- }
1879
- if (listenerReg.test(key)) {
1880
- if (typeof value === 'function') {
1881
- nativeRenderer.listen(nativeNode, key, value, isSvg);
1882
- }
1883
- continue;
1884
- }
1885
- if (key === refKey) {
1886
- bindRefs = value;
1887
- continue;
1888
- }
1889
- nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1890
- }
1801
+ });
1891
1802
  if (!updatedChildren) {
1892
1803
  newAtom.child = oldAtom.child;
1893
1804
  reuseElementChildrenView(nativeRenderer, newAtom);