Some questions about aurelia-store

I’ve recently started using aurelia-store to tackle global filters in our application (e.g. when toggling a global tag filter, all resources throughout the app should be filtered on that tag), though I’m running in some issues and would like your advise.

Take the following sample component:

@connectTo<State>({
  selector: {
     foo: store => store.state.pipe(pluck("foo")),
     filters: store => store.state.pipe(pluck("filters"))
  }
})
export class MySampleComponent {
  foo;
  filters;

  filteredFoo;

  private _doSomethingHeavy() {
     // Heavy lifting 
  }

  private _computeFilteredFoo() {
     // complex computation
  }

  fooChanged() { 
    this._doSomethingHeavy();
    this._computeFilteredFoo();
  }

  filtersChanged() {
    this._computeFilteredFoo();      
  }
}

With this component there are 2 major issues:

  1. Whenever anything in the state changes (even something unrelated), both foo and filters are also triggered as changed, I can assume this is because the overall state changed. This kills performance however since now any state change will compute heavy work and causes rendering issues. I would be able to work around this by either mutating the existing state instead or do some complex merging with a local copy, neither sound right. What would be the best practice here?

  2. Whenever fooChanged or filtersChanged gets called, neither foo or filters have been set yet, so I would either have to accept the new state as an argument, or schedule a processing job in the background. Is this a bug? For clarification:

// assuming current foo is 1
store.dispatch(updateFoo, 2);

fooChanged(newFoo) {
  console.log(this.foo); // 1
  console.log(newfoo); // 2
  window.setTimeout(() => {
   console.log(this.foo); // 2
  );
}

1 Like

As for the first question you can make use of this operator from rxjs to only get a state in your subscription once the value changed https://www.learnrxjs.io/learn-rxjs/operators/filtering/distinctuntilchanged

With regards to the second, yep the changed handlers are firing before the actual property is set so you’d have to take the params (newstate, oldstate). In general you should try to keep changedhandlers as pure functions without referencing this for sideeffects exactly for the reason of recomputes.

Also with regards to the timing there is already a PR in place https://github.com/aurelia/store/pull/82 which we held off merging as it’s a breaking change. Granted though this is a deviation from standard Aurelia and ultimately should get merged. Maybe you can leave your comment in the PR or linked issue so we have more thoughts/votes

5 Likes

Since I came across it yesterday evening, I want to share the example for using distinctUntilChanged @zewa666 gave in this thread:

@connectTo({
  selector: {
    foo: store => store.state.pipe(pluck('foo'), distinctUntilChanged()),
    bar: store => store.state.pipe(pluck('bar'), distinctUntilChanged())
  }
})
2 Likes

Also, if you do know, what you want to do, but not how the operator is called / if there is one for your desired behaviour:
https://rxjs-dev.firebaseapp.com/operator-decision-tree

4 Likes

Oh that’s a neat helper page thx for sharing.

2 Likes