1

In my Angular app , i'm working to set up a state management logic using BehaviourSubject

So , i ve in my store file this :

myStoreData = new BehaviourSubject([])

in my actions file i ve this :

export const SAVE_DATA_IN_CONTEXT = '[User] Save user the incoming data';

So that , in the component , when needed , the method to call is this:

click(newData){
  this.reducerService('SAVE_DATA_IN_CONTEXT' , newData)
}

My purpose , is that in my reducer , i won't just send to the store (behaviourSubject) the new data , but i want that it appends it with the existing one ( i doosn't want that the new value replace the existing one) :

As a result it would look like this :

data to send to BehaviourSubject (array) = existing data (array of objects) + new data (object)

my reducer looks like this , and i tried that :

public dispatchAction(actionTag: string, newDataPayload: any | null): void {
    
    switch (actionTag) {
      case ActionsTags.SAVE_DATA_IN_CONTEXT :
        const newDataToSet = [...Stores.myStoreData.getValue() , ...newDataPayload ];
        Stores.myStoreData.next(newDataPayload);
        break;

}

Since i'm convinced that the method getValue() is a bad practise , and i won't pass by Stores.myStoreData.subscribe() because i can't handle the unsubscription and the user click method would be repetitive (possibly the subscribe would open a new subscription each time)

I'm looking fo a better manner to do it properly (maybe change the BehaviouSubject)

Suggestions ??

firasKoubaa
  • 6,439
  • 25
  • 79
  • 148
  • you should probably use ngrx to do that , and simply get a state then `data: [...state.data, ...newData]` – Jean-Xavier Raynaud Dec 09 '20 at 12:02
  • wanna set the equivalent of ngrx with rxjs and behaviourSubjects @Jean-XavierRaynaud – firasKoubaa Dec 09 '20 at 12:03
  • in that case you have to use .value of the behaviorSubject, under the hood ngrx use behaviorSubjects to create the state and use .value when you need to access it. – Jean-Xavier Raynaud Dec 09 '20 at 12:09
  • May I ask why you're going through the whole process of basically re implementing the ngrx logic without using it ? – Jean-Xavier Raynaud Dec 09 '20 at 12:10
  • there is a differrence betwen .value and getVlaue() of behaviourSubject ? – firasKoubaa Dec 09 '20 at 12:11
  • i won t use ngRx (or any other 3rd part library) , and it s awesome yo combinate rxjs tools for it (it s a prototype ) – firasKoubaa Dec 09 '20 at 12:13
  • I think getValue() was dropped in rxjs 4 or 5, edit: wasn't dropped, they just added value for clarity in rxjs5 – Jean-Xavier Raynaud Dec 09 '20 at 12:13
  • getValue() and value() are exactly the same : https://github.com/ReactiveX/rxjs/blob/master/src/internal/BehaviorSubject.ts#L19 – Jean-Xavier Raynaud Dec 09 '20 at 12:15
  • Ok so both of them seem to be bad ways , there are no other way to do it properly ? – firasKoubaa Dec 09 '20 at 12:19
  • Why do you assume they are bad ways ? – Jean-Xavier Raynaud Dec 09 '20 at 12:30
  • they are deperacated – firasKoubaa Dec 09 '20 at 12:32
  • They aren't. getValue() is deprecated for a Subject, not a BehaviorSubject. The whole purpose of a behavior subject is to provide a direct access to the value, not as an observable but as a getter. That's why a BS requires an initial Value to be instanciated as it must always have a defined internal _value attribute defined to be able to always provide a getter. – Jean-Xavier Raynaud Dec 09 '20 at 13:25
  • @Jean-XavierRaynaud ok cool – firasKoubaa Dec 09 '20 at 13:33
  • looking into it, there's this post https://stackoverflow.com/questions/37089977/how-to-get-current-value-of-rxjs-subject-or-observable/45227115#45227115 where one of the core member of rxjs says that using value/getValue() is a sign that something is wrong in 99.99% of the cases. I tend to agree if you use bs.value() in a comp instead of having a private bs in a service and a public asObservable() in that service. – Jean-Xavier Raynaud Dec 09 '20 at 14:01
  • However in your use case, building a redux like logic, using .value in the reducer seems to be the correct logic to me, mainly because reducers are supposed to be pure functions, and thus any kind of subscription seems illogical to me. So I would say that in reducers calling the state directly through .value seems to me to be in the 0.01% of edge cases. – Jean-Xavier Raynaud Dec 09 '20 at 14:04

1 Answers1

1

As explained in some comments under your question, there are libraries for this and you should probably use them instead of reinventing the wheel.

That said, lets assume this is for learning purpose and do it anyway.

I'd recommend to embrace reactive programming and build everything as streams. Then make a super tiny layer into a service to wrap this so you can provide it through dependency injection.

For the reactive bit, I'd just have a subject that I'd pass actions to. Based onto this, I'd have a stream maintaining the state. This would look like the following:

const action$ = new Subject();

const state$ = action$.pipe(
  scan((state, action) => {
    switch (action.type) {
      case 'some_action':
        // todo: return a new state
      default:
        state;
    }
  })
);

Then if you want to provide this into a service you could simply do:

@Injectable()
export class Store {
  private action$ = new Subject();

  public state$ = action$.pipe(
    scan((state, action) => {
      switch (action.type) {
        case 'some_action':
          // todo: return a new state
        default:
          state;
      }
    }),
    shareReplay(1)
  );

  public dispatch(action): void {
    this.action$.next(action)
  }
}
maxime1992
  • 22,502
  • 10
  • 80
  • 121
  • the purpose is to combine the data to pass as next (data_to_pass = oldvalue + newValue) – firasKoubaa Dec 09 '20 at 13:21
  • I don't get it. Reactive programming means that Actions and Reducers are supposed to be pure functions, not streams. Selectors are streams but that's out of the scope. – Jean-Xavier Raynaud Dec 09 '20 at 13:54
  • Reactive programming doesn't mean anything about actions and reducers. Actions are simple object which can be serialised, reducers are pure functions which take a current state and based on an action returns a new state (this is the equivalent of the scan above). Selectors are not streams. Selectors are pure functions to which you pass other selectors to produce a different output. This ouput can be computed from data coming from the store or simply other data based on other selectors. – maxime1992 Dec 09 '20 at 14:18
  • 1
    But reactive programming is just about streams. It's not tight to any state management concerns like actions, reducers or selectors. – maxime1992 Dec 09 '20 at 14:19