@viewfly/core 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  });
@@ -1301,11 +1135,20 @@ function withAnnotation(annotation, componentSetup) {
1301
1135
  return function (props) {
1302
1136
  const instance = getCurrentInstance();
1303
1137
  const parentInjector = injectMap.get(instance) || getInjector(instance.parentComponent);
1304
- const injector = new ReflectiveInjector(parentInjector, annotation.providers || [], annotation.scope);
1138
+ const injector = new ReflectiveInjector(parentInjector, [{
1139
+ provide: Injector,
1140
+ useFactory() {
1141
+ return injector;
1142
+ }
1143
+ }, ...(annotation.providers || [])], annotation.scope);
1305
1144
  injectMap.set(instance, injector);
1306
1145
  return componentSetup(props);
1307
1146
  };
1308
1147
  }
1148
+ /**
1149
+ * @deprecated
1150
+ * @param props
1151
+ */
1309
1152
  function Context(props) {
1310
1153
  function createContextComponent(providers) {
1311
1154
  return withAnnotation({
@@ -1340,11 +1183,89 @@ function withMemo(canUseMemo, render) {
1340
1183
  };
1341
1184
  }
1342
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
+
1343
1265
  const ElementNamespaceMap = {
1344
1266
  svg: 'svg',
1345
1267
  math: 'mathml',
1346
1268
  };
1347
- const componentViewCache = new WeakMap();
1348
1269
  const listenerReg = /^on[A-Z]/;
1349
1270
  function createRenderer(component, nativeRenderer, namespace) {
1350
1271
  let isInit = true;
@@ -1368,7 +1289,7 @@ function createRenderer(component, nativeRenderer, namespace) {
1368
1289
  });
1369
1290
  }
1370
1291
  else {
1371
- updateView(nativeRenderer, component, false);
1292
+ deepUpdateByComponentDirtyTree(nativeRenderer, component, false);
1372
1293
  }
1373
1294
  };
1374
1295
  }
@@ -1393,37 +1314,39 @@ function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1393
1314
  child = child.sibling;
1394
1315
  }
1395
1316
  }
1396
- 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) {
1397
1323
  if (component.dirty) {
1398
- const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1399
- applyChanges(nativeRenderer, component, atom, {
1400
- host,
1401
- isParent,
1402
- rootHost
1403
- }, 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();
1404
1342
  }
1405
1343
  else if (component.changed) {
1406
1344
  component.changedSubComponents.forEach(child => {
1407
- updateView(nativeRenderer, child, needMove);
1345
+ deepUpdateByComponentDirtyTree(nativeRenderer, child, needMove);
1408
1346
  });
1409
1347
  component.rendered();
1410
1348
  }
1411
1349
  }
1412
- function applyChanges(nativeRenderer, component, atom, context, needMove) {
1413
- const diffAtom = atom.child;
1414
- component.update(component.props, newTemplate => {
1415
- atom.child = createChildChain(newTemplate, atom.namespace);
1416
- diff(nativeRenderer, component, atom.child, diffAtom, context, needMove);
1417
- const next = atom.sibling;
1418
- if (next && next.jsxNode instanceof Component) {
1419
- const view = componentViewCache.get(next.jsxNode);
1420
- view.host = context.host;
1421
- view.isParent = context.isParent;
1422
- }
1423
- }, (skipSubComponentDiff) => {
1424
- reuseComponentView(nativeRenderer, atom, context, needMove, skipSubComponentDiff);
1425
- });
1426
- }
1427
1350
  function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1428
1351
  const commits = [];
1429
1352
  function changeOffset() {
@@ -1439,7 +1362,8 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1439
1362
  dirtyDiffAtom = dirtyDiffAtom.sibling;
1440
1363
  }
1441
1364
  let offset = 0;
1442
- for (let i = 0; i < commits.length; i++) {
1365
+ const len = commits.length;
1366
+ for (let i = 0; i < len; i++) {
1443
1367
  const commit = commits[i];
1444
1368
  while (oldAtom) {
1445
1369
  if (oldAtom.index <= i) {
@@ -1449,7 +1373,7 @@ function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMo
1449
1373
  }
1450
1374
  break;
1451
1375
  }
1452
- commit(offset, needMove);
1376
+ commit.callback(commit.params, offset, needMove);
1453
1377
  }
1454
1378
  }
1455
1379
  function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, parentComponent, effect) {
@@ -1458,17 +1382,19 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1458
1382
  while (oldAtom) {
1459
1383
  const newAtomType = newAtom.type;
1460
1384
  if (oldAtom.type === newAtomType && oldAtom.nodeType === newAtom.nodeType && oldAtom.key === newAtom.key) {
1461
- let commit;
1462
- if (newAtomType === TextAtomType) {
1463
- commit = updateText(newAtom, oldAtom, nativeRenderer, context);
1464
- }
1465
- else if (newAtomType === ComponentAtomType) {
1466
- commit = updateComponent(newAtom, oldAtom, nativeRenderer, context);
1467
- }
1468
- else {
1469
- commit = updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent);
1470
- }
1471
- 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
+ });
1472
1398
  const next = oldAtom.sibling;
1473
1399
  if (!prev) {
1474
1400
  return next;
@@ -1479,81 +1405,84 @@ function createChanges(newAtom, oldAtom, nativeRenderer, commits, context, paren
1479
1405
  prev = oldAtom;
1480
1406
  oldAtom = oldAtom.sibling;
1481
1407
  }
1482
- 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
+ });
1483
1419
  return startDiffAtom;
1484
1420
  }
1485
- function createNewView(start, nativeRenderer, context, parentComponent, effect) {
1486
- return function () {
1487
- buildView(nativeRenderer, parentComponent, start, context);
1488
- effect();
1489
- };
1421
+ function patchUpdate(params) {
1422
+ const { nativeRenderer, parentComponent, newAtom, context, effect } = params;
1423
+ buildView(nativeRenderer, parentComponent, newAtom, context);
1424
+ effect();
1490
1425
  }
1491
- function updateText(newAtom, oldAtom, nativeRenderer, context) {
1492
- return function (offset, needMove) {
1493
- const nativeNode = oldAtom.nativeNode;
1494
- newAtom.nativeNode = nativeNode;
1495
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1496
- insertNode(nativeRenderer, newAtom, context);
1497
- }
1498
- context.host = nativeNode;
1499
- context.isParent = false;
1500
- };
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;
1501
1435
  }
1502
- function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponent) {
1503
- return function (offset, needMove) {
1504
- newAtom.nativeNode = oldAtom.nativeNode;
1505
- if (needMove || newAtom.index - offset !== oldAtom.index) {
1506
- insertNode(nativeRenderer, newAtom, context);
1507
- }
1508
- context.host = newAtom.nativeNode;
1509
- context.isParent = false;
1510
- updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1511
- host: newAtom.nativeNode,
1512
- isParent: true,
1513
- rootHost: context.rootHost
1514
- });
1515
- };
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
+ });
1516
1449
  }
1517
- function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1518
- return function (offset, needMove) {
1519
- const component = reusedAtom.jsxNode;
1520
- const newProps = newAtom.jsxNode.props;
1521
- const portalHost = component.instance.$portalHost;
1522
- context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1523
- componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1524
- newAtom.jsxNode = component;
1525
- component.update(newProps, newTemplate => {
1526
- if (newTemplate) {
1527
- newAtom.child = createChildChain(newTemplate, newAtom.namespace);
1528
- }
1529
- if (newAtom.child) {
1530
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1531
- }
1532
- else if (reusedAtom.child) {
1533
- let atom = reusedAtom.child;
1534
- while (atom) {
1535
- cleanView(nativeRenderer, atom, true);
1536
- atom = atom.sibling;
1537
- }
1538
- }
1539
- }, (skipSubComponentDiff) => {
1540
- newAtom.child = reusedAtom.child;
1541
- reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index, skipSubComponentDiff);
1542
- });
1543
- };
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();
1544
1479
  }
1545
1480
  function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1546
1481
  const updateContext = (atom) => {
1547
1482
  if (atom.jsxNode instanceof Component) {
1548
- if (skipSubComponentDiff || !moveView) {
1549
- let child = atom.child;
1550
- while (child) {
1551
- updateContext(child);
1552
- child = child.sibling;
1553
- }
1554
- }
1555
- else {
1556
- applyChanges(nativeRenderer, atom.jsxNode, atom, context, true);
1483
+ reuseComponentView(nativeRenderer, atom.child, context, moveView, skipSubComponentDiff);
1484
+ if (!skipSubComponentDiff) {
1485
+ deepUpdateByComponentDirtyTree(nativeRenderer, atom.jsxNode, moveView);
1557
1486
  }
1558
1487
  }
1559
1488
  else {
@@ -1574,7 +1503,7 @@ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponen
1574
1503
  let child = atom.child;
1575
1504
  while (child) {
1576
1505
  if (child.jsxNode instanceof Component) {
1577
- updateView(nativeRenderer, child.jsxNode, false);
1506
+ deepUpdateByComponentDirtyTree(nativeRenderer, child.jsxNode, false);
1578
1507
  }
1579
1508
  else {
1580
1509
  reuseElementChildrenView(nativeRenderer, child);
@@ -1621,7 +1550,7 @@ function componentRender(nativeRenderer, component, from, context) {
1621
1550
  component.render((template, portalHost) => {
1622
1551
  from.child = createChildChain(template, from.namespace);
1623
1552
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1624
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1553
+ component.viewMetadata = Object.assign({ atom: from }, context);
1625
1554
  let child = from.child;
1626
1555
  while (child) {
1627
1556
  buildView(nativeRenderer, component, child, context);
@@ -1646,14 +1575,14 @@ function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, namespace, key)
1646
1575
  }
1647
1576
  function createChainByNode(jsxNode, prevAtom, elementNamespace) {
1648
1577
  const type = typeof jsxNode;
1649
- if (jsxNode !== null && type !== 'undefined' && type !== 'boolean') {
1650
- if (typeof jsxNode === 'string') {
1578
+ if (jsxNode != null && type !== 'boolean') {
1579
+ if (type === 'string') {
1651
1580
  return createChainByJSXNode(TextAtomType, jsxNode, jsxNode, prevAtom, elementNamespace);
1652
1581
  }
1653
- if (Array.isArray(jsxNode)) {
1654
- return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1655
- }
1656
1582
  if (type === 'object') {
1583
+ if (Array.isArray(jsxNode)) {
1584
+ return createChainByChildren(jsxNode, prevAtom, elementNamespace);
1585
+ }
1657
1586
  const nodeType = typeof jsxNode.type;
1658
1587
  if (nodeType === 'string') {
1659
1588
  return createChainByJSXNode(ElementAtomType, jsxNode, jsxNode.type, prevAtom, elementNamespace || ElementNamespaceMap[jsxNode.type], jsxNode.key);
@@ -1764,43 +1693,66 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1764
1693
  reuseElementChildrenView(nativeRenderer, newAtom);
1765
1694
  return;
1766
1695
  }
1767
- const changes = getObjectChanges(newVNode.props, oldVNode.props);
1768
1696
  let unBindRefs;
1769
1697
  let bindRefs;
1770
1698
  let updatedChildren = false;
1771
- let len = changes.remove.length;
1772
- for (let i = 0; i < len; i++) {
1773
- const [key, value] = changes.remove[i];
1699
+ comparePropsWithCallbacks(oldVNode.props, newVNode.props, (key, oldValue) => {
1774
1700
  if (key === 'children') {
1775
1701
  updatedChildren = true;
1776
1702
  cleanElementChildren(oldAtom, nativeRenderer);
1777
- continue;
1703
+ return;
1778
1704
  }
1779
1705
  if (key === 'class') {
1780
1706
  nativeRenderer.setClass(nativeNode, '', isSvg);
1781
- continue;
1707
+ return;
1782
1708
  }
1783
1709
  if (key === 'style') {
1784
- for (const styleName in styleToObject(value)) {
1710
+ for (const styleName in styleToObject(oldValue)) {
1785
1711
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1786
1712
  }
1787
- continue;
1713
+ return;
1788
1714
  }
1789
1715
  if (listenerReg.test(key)) {
1790
- if (typeof value === 'function') {
1791
- nativeRenderer.unListen(nativeNode, key, value, isSvg);
1716
+ if (typeof oldValue === 'function') {
1717
+ nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1792
1718
  }
1793
- continue;
1719
+ return;
1794
1720
  }
1795
1721
  if (key === refKey) {
1796
- unBindRefs = value;
1797
- continue;
1722
+ unBindRefs = oldValue;
1723
+ return;
1798
1724
  }
1799
1725
  nativeRenderer.removeProperty(nativeNode, key, isSvg);
1800
- }
1801
- len = changes.replace.length;
1802
- for (let i = 0; i < len; i++) {
1803
- 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) => {
1804
1756
  if (key === 'children') {
1805
1757
  updatedChildren = true;
1806
1758
  newAtom.child = createElementChildren(newVNode.type, newValue, isSvg);
@@ -1813,7 +1765,7 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1813
1765
  else {
1814
1766
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1815
1767
  }
1816
- continue;
1768
+ return;
1817
1769
  }
1818
1770
  if (key === 'class') {
1819
1771
  const oldClassName = classToString(oldValue);
@@ -1821,62 +1773,30 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1821
1773
  if (oldClassName !== newClassName) {
1822
1774
  nativeRenderer.setClass(nativeNode, newClassName, isSvg);
1823
1775
  }
1824
- continue;
1776
+ return;
1825
1777
  }
1826
1778
  if (key === 'style') {
1827
- const styleChanges = getObjectChanges(styleToObject(newValue) || {}, styleToObject(oldValue) || {});
1828
- for (const [styleName] of styleChanges.remove) {
1779
+ comparePropsWithCallbacks(styleToObject(oldValue), styleToObject(newValue), styleName => {
1829
1780
  nativeRenderer.removeStyle(nativeNode, styleName, isSvg);
1830
- }
1831
- for (const [styleName, styleValue] of [...styleChanges.add, ...styleChanges.replace]) {
1781
+ }, (styleName, styleValue) => {
1832
1782
  nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1833
- }
1834
- continue;
1783
+ }, (styleName, styleValue) => {
1784
+ nativeRenderer.setStyle(nativeNode, styleName, styleValue, isSvg);
1785
+ });
1786
+ return;
1835
1787
  }
1836
1788
  if (listenerReg.test(key)) {
1837
1789
  nativeRenderer.unListen(nativeNode, key, oldValue, isSvg);
1838
1790
  nativeRenderer.listen(nativeNode, key, newValue, isSvg);
1839
- continue;
1791
+ return;
1840
1792
  }
1841
1793
  if (key === refKey) {
1842
1794
  unBindRefs = oldValue;
1843
1795
  bindRefs = newValue;
1844
- continue;
1796
+ return;
1845
1797
  }
1846
1798
  nativeRenderer.setProperty(nativeNode, key, newValue, isSvg);
1847
- }
1848
- len = changes.add.length;
1849
- for (let i = 0; i < len; i++) {
1850
- const [key, value] = changes.add[i];
1851
- if (key === 'children') {
1852
- updatedChildren = true;
1853
- newAtom.child = createElementChildren(newVNode.type, value, isSvg);
1854
- buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1855
- continue;
1856
- }
1857
- if (key === 'class') {
1858
- nativeRenderer.setClass(nativeNode, classToString(value), isSvg);
1859
- continue;
1860
- }
1861
- if (key === 'style') {
1862
- const styleObj = styleToObject(value);
1863
- for (const styleName in styleObj) {
1864
- nativeRenderer.setStyle(nativeNode, styleName, styleObj[styleName], isSvg);
1865
- }
1866
- continue;
1867
- }
1868
- if (listenerReg.test(key)) {
1869
- if (typeof value === 'function') {
1870
- nativeRenderer.listen(nativeNode, key, value, isSvg);
1871
- }
1872
- continue;
1873
- }
1874
- if (key === refKey) {
1875
- bindRefs = value;
1876
- continue;
1877
- }
1878
- nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1879
- }
1799
+ });
1880
1800
  if (!updatedChildren) {
1881
1801
  newAtom.child = oldAtom.child;
1882
1802
  reuseElementChildrenView(nativeRenderer, newAtom);