@ngxs/store 18.1.1-dev.master-76347ef → 18.1.1-dev.master-e935e57

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.
@@ -1025,25 +1025,25 @@ class StateContextFactory {
1025
1025
  /**
1026
1026
  * Create the state context
1027
1027
  */
1028
- createStateContext(mappedStore) {
1028
+ createStateContext(path) {
1029
1029
  const root = this._internalStateOperations.getRootStateOperations();
1030
1030
  return {
1031
1031
  getState() {
1032
1032
  const currentAppState = root.getState();
1033
- return getState(currentAppState, mappedStore.path);
1033
+ return getState(currentAppState, path);
1034
1034
  },
1035
1035
  patchState(val) {
1036
1036
  const currentAppState = root.getState();
1037
1037
  const patchOperator = simplePatch(val);
1038
- setStateFromOperator(root, currentAppState, patchOperator, mappedStore.path);
1038
+ setStateFromOperator(root, currentAppState, patchOperator, path);
1039
1039
  },
1040
1040
  setState(val) {
1041
1041
  const currentAppState = root.getState();
1042
1042
  if (isStateOperator(val)) {
1043
- setStateFromOperator(root, currentAppState, val, mappedStore.path);
1043
+ setStateFromOperator(root, currentAppState, val, path);
1044
1044
  }
1045
1045
  else {
1046
- setStateValue(root, currentAppState, val, mappedStore.path);
1046
+ setStateValue(root, currentAppState, val, path);
1047
1047
  }
1048
1048
  },
1049
1049
  dispatch(actions) {
@@ -1237,6 +1237,12 @@ class StateFactory {
1237
1237
  this._actionsSubscription = null;
1238
1238
  this._propGetter = inject(ɵPROP_GETTER);
1239
1239
  this._ngxsUnhandledErrorHandler = null;
1240
+ // Instead of going over the states list every time an action is dispatched,
1241
+ // we are constructing a map of action types to lists of action metadata.
1242
+ // If the `@@Init` action is handled in two different states, the action
1243
+ // metadata list will contain two objects that have the state `instance` and
1244
+ // method names to be used as action handlers (decorated with `@Action(InitState)`).
1245
+ this._actionTypeToMetasMap = new Map();
1240
1246
  this._states = [];
1241
1247
  this._statesByName = {};
1242
1248
  this._statePaths = {};
@@ -1277,6 +1283,11 @@ class StateFactory {
1277
1283
  return context;
1278
1284
  });
1279
1285
  }
1286
+ get actionTypeToMetasMap() {
1287
+ return this._parentFactory
1288
+ ? this._parentFactory.actionTypeToMetasMap
1289
+ : this._actionTypeToMetasMap;
1290
+ }
1280
1291
  get states() {
1281
1292
  return this._parentFactory ? this._parentFactory.states : this._states;
1282
1293
  }
@@ -1331,6 +1342,7 @@ class StateFactory {
1331
1342
  bootstrappedStores.push(stateMap);
1332
1343
  }
1333
1344
  this.states.push(stateMap);
1345
+ this.hydrateActionMetasMap(stateMap);
1334
1346
  }
1335
1347
  return bootstrappedStores;
1336
1348
  }
@@ -1377,55 +1389,53 @@ class StateFactory {
1377
1389
  // Determines whether the dispatched action has been handled, this is assigned
1378
1390
  // to `true` within the below `for` loop if any `actionMetas` has been found.
1379
1391
  let actionHasBeenHandled = false;
1380
- for (const metadata of this.states) {
1381
- const actionMetas = metadata.actions[type];
1382
- if (actionMetas) {
1383
- for (const actionMeta of actionMetas) {
1384
- const stateContext = this._stateContextFactory.createStateContext(metadata);
1385
- try {
1386
- let result = metadata.instance[actionMeta.fn](stateContext, action);
1387
- // We need to use `isPromise` instead of checking whether
1388
- // `result instanceof Promise`. In zone.js patched environments, `global.Promise`
1389
- // is the `ZoneAwarePromise`. Some APIs, which are likely not patched by zone.js
1390
- // for certain reasons, might not work with `instanceof`. For instance, the dynamic
1391
- // import returns a native promise (not a `ZoneAwarePromise`), causing this check to
1392
- // be falsy.
1393
- if (_isPromise(result)) {
1394
- result = from(result);
1395
- }
1396
- if (isObservable(result)) {
1397
- // If this observable has been completed w/o emitting
1398
- // any value then we wouldn't want to complete the whole chain
1399
- // of actions. Since if any observable completes then
1400
- // action will be canceled.
1401
- // For instance if any action handler would've had such statement:
1402
- // `handler(ctx) { return EMPTY; }`
1403
- // then the action will be canceled.
1404
- // See https://github.com/ngxs/store/issues/1568
1405
- result = result.pipe(mergeMap((value) => {
1406
- if (_isPromise(value)) {
1407
- return from(value);
1408
- }
1409
- if (isObservable(value)) {
1410
- return value;
1411
- }
1412
- return of(value);
1413
- }), defaultIfEmpty({}));
1414
- if (actionMeta.options.cancelUncompleted) {
1415
- // todo: ofActionDispatched should be used with action class
1416
- result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
1392
+ const actionMetas = this.actionTypeToMetasMap.get(type);
1393
+ if (actionMetas) {
1394
+ for (const actionMeta of actionMetas) {
1395
+ const stateContext = this._stateContextFactory.createStateContext(actionMeta.path);
1396
+ let result;
1397
+ try {
1398
+ result = actionMeta.instance[actionMeta.fn](stateContext, action);
1399
+ // We need to use `isPromise` instead of checking whether
1400
+ // `result instanceof Promise`. In zone.js patched environments, `global.Promise`
1401
+ // is the `ZoneAwarePromise`. Some APIs, which are likely not patched by zone.js
1402
+ // for certain reasons, might not work with `instanceof`. For instance, the dynamic
1403
+ // import returns a native promise (not a `ZoneAwarePromise`), causing this check to
1404
+ // be falsy.
1405
+ if (_isPromise(result)) {
1406
+ result = from(result);
1407
+ }
1408
+ if (isObservable(result)) {
1409
+ result = result.pipe(mergeMap((value) => {
1410
+ if (_isPromise(value)) {
1411
+ return from(value);
1417
1412
  }
1413
+ if (isObservable(value)) {
1414
+ return value;
1415
+ }
1416
+ return of(value);
1417
+ }),
1418
+ // If this observable has completed without emitting any values,
1419
+ // we wouldn't want to complete the entire chain of actions.
1420
+ // If any observable completes, then the action will be canceled.
1421
+ // For instance, if any action handler had a statement like
1422
+ // `handler(ctx) { return EMPTY; }`, then the action would be canceled.
1423
+ // See https://github.com/ngxs/store/issues/1568
1424
+ defaultIfEmpty({}));
1425
+ if (actionMeta.options.cancelUncompleted) {
1426
+ // todo: ofActionDispatched should be used with action class
1427
+ result = result.pipe(takeUntil(dispatched$.pipe(ofActionDispatched(action))));
1418
1428
  }
1419
- else {
1420
- result = of({}).pipe(shareReplay());
1421
- }
1422
- results.push(result);
1423
1429
  }
1424
- catch (e) {
1425
- results.push(throwError(e));
1430
+ else {
1431
+ result = of({}).pipe(shareReplay());
1426
1432
  }
1427
- actionHasBeenHandled = true;
1428
1433
  }
1434
+ catch (e) {
1435
+ result = throwError(e);
1436
+ }
1437
+ results.push(result);
1438
+ actionHasBeenHandled = true;
1429
1439
  }
1430
1440
  }
1431
1441
  // The `NgxsUnhandledActionsLogger` is a tree-shakable class which functions
@@ -1435,9 +1445,7 @@ class StateFactory {
1435
1445
  // The `NgxsUnhandledActionsLogger` will not be resolved by the injector if the
1436
1446
  // `NgxsDevelopmentModule` is not provided. It's enough to check whether the `injector.get`
1437
1447
  // didn't return `null` so we may ensure the module has been imported.
1438
- if (unhandledActionsLogger) {
1439
- unhandledActionsLogger.warn(action);
1440
- }
1448
+ unhandledActionsLogger?.warn(action);
1441
1449
  }
1442
1450
  if (!results.length) {
1443
1451
  results.push(of({}));
@@ -1473,6 +1481,28 @@ class StateFactory {
1473
1481
  // its lifecycle is in 'bootstrapped' state.
1474
1482
  return this.statesByName[name] && valueIsBootstrappedInInitialState;
1475
1483
  }
1484
+ hydrateActionMetasMap({ path, actions, instance }) {
1485
+ const actionTypeToMetasMap = this.actionTypeToMetasMap;
1486
+ for (const actionType of Object.keys(actions)) {
1487
+ // Initialize the map entry if it does not already exist for that
1488
+ // action type. Note that action types may overlap between states,
1489
+ // as the same action can be handled by different states.
1490
+ if (!actionTypeToMetasMap.has(actionType)) {
1491
+ actionTypeToMetasMap.set(actionType, []);
1492
+ }
1493
+ const extendedActionMetas = actionTypeToMetasMap.get(actionType);
1494
+ extendedActionMetas.push(
1495
+ // This involves combining each individual action metadata with
1496
+ // the state instance and the path—essentially everything needed
1497
+ // to invoke an action. This eliminates the need to loop over states
1498
+ // every time an action is dispatched.
1499
+ ...actions[actionType].map(actionMeta => ({
1500
+ ...actionMeta,
1501
+ path,
1502
+ instance
1503
+ })));
1504
+ }
1505
+ }
1476
1506
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory, deps: [{ token: i0.Injector }, { token: NgxsConfig }, { token: StateFactory, optional: true, skipSelf: true }, { token: InternalActions }, { token: InternalDispatchedActionResults }, { token: StateContextFactory }, { token: _INITIAL_STATE_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1477
1507
  /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: StateFactory }); }
1478
1508
  }
@@ -1705,7 +1735,7 @@ class LifecycleStateManager {
1705
1735
  }
1706
1736
  }
1707
1737
  _getStateContext(mappedStore) {
1708
- return this._stateContextFactory.createStateContext(mappedStore);
1738
+ return this._stateContextFactory.createStateContext(mappedStore.path);
1709
1739
  }
1710
1740
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: LifecycleStateManager, deps: [{ token: Store }, { token: InternalStateOperations }, { token: StateContextFactory }, { token: i1.ɵNgxsAppBootstrappedState }], target: i0.ɵɵFactoryTarget.Injectable }); }
1711
1741
  /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.6", ngImport: i0, type: LifecycleStateManager, providedIn: 'root' }); }