firasKoubaa
firasKoubaa

Reputation: 6867

RxJs : How to append data to BehaviourSubject (concat the last value with new one)

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 ??

Upvotes: 1

Views: 876

Answers (1)

maxime1992
maxime1992

Reputation: 23803

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)
  }
}

Upvotes: 1

Related Questions