2

I have a Redux (well, rxjs-store) structure that's very generic. Basically, my data-types are all different versions of a generic data structure called an "Element" (each defined by a different "ElementType").

The goal is I don't have to add a whole new set of data objects to the store, API, backend, database etc when a new data object comes along.

This is working well so far, but I've come across a problem with Redux & Reselect where the selector is re-calculating multiple times.

Here's an example. For my page I need to load 4 sets of Elements of a particular type:

// subscribe to data
const elements$ = Observable.combineLatest(
  this.elementTypeManager.getElementTypeByName('DistributionNetworkNode'),
  this.elementTypeManager.getElementTypeByName('Socket'),
  this.elementTypeManager.getElementTypeByName('Area'),
  this.elementTypeManager.getElementTypeByName('DemandType'))
  .switchMap(nodeAndSocketTypes => Observable.combineLatest(
    this.elementManager.getElementsByType(nodeAndSocketTypes[0].id),
    this.elementManager.getElementsByType(nodeAndSocketTypes[1].id),
    this.elementManager.getElementsByType(nodeAndSocketTypes[2].id),
    this.elementManager.getElementsByType(nodeAndSocketTypes[3].id)));

The elementTypeManager and elementManager is the service that sends out a Redux Action, and uses reselect to query the store, like this:

public getElementsByType(elementTypeId: AAGUID): Observable<Elements> {
  // dispatch an action to the store (triggers http and storing data)
  this.store.dispatch(this.elementActions.loadElementsForType(elementTypeId));

  // use reselect to query store
  return this.store.select(getElementsByTypeFactory(elementTypeId));
}

The Load Elements action triggers a http request to retrieve the data, and emits a Store Elements Data action, which the reducer takes and puts in the store.

The reselect selector is pretty simple and looks like this:

export const getElements = (state: AppState) => state.elements;

export function getElementsByTypeFactory(elementTypeId: AAGUID, includeValues: boolean = false) {
  return createSelector([getElements],
                        (elements: Elements) => elements.filter(e => e.elementTypeId === elementTypeId));
}

It takes the elements, and filters by the specified type.

The problem is, the actions are called in sequence:

Load Elements (DistributionNetworkNode)
Load Elements (Socket)
Load Elements (Area)
Load Elements (DemandType)

Then, stored in sequence:

Store Element Data (DistributionNetworkNode)
Store Element Data (Socket)
Store Element Data (Area)
Store Element Data (DemandType)

Each time the reducer puts data into the store, reselect recalculates. Of course, it hasn't finished putting all the data in yet, so the other selectors return 0 results.

As a result, my CombineLatest emits 4 times, one with just the DistributionNetworkNode data, one with the DistributionNetworkNode and Socket data, one with the DistributionNetworkNode, Socket and Area data etc etc.

This is a continuous problem with the way my data is structured and how I'm using re-select, and I'm not sure how to overcome it without compromising the generic way the data is structured.

How can make sure all my Store Element Data actions have taken place before querying/emitting data with reselect?

Joe
  • 6,773
  • 2
  • 47
  • 81
  • did you ever figure out an answer to this question? I'm having trouble with this too. – David Feb 01 '19 at 00:08
  • I didn't I'm afraid, stopped working on the project so never really continued trying to find a solution. – Joe Feb 01 '19 at 08:18

0 Answers0