spierala / mini-rx-store

MiniRx - The reactive state management platform
https://mini-rx.io
Other
169 stars 9 forks source link

Edit Items which have been subscribed to #189

Closed theSilverFisch closed 1 year ago

theSilverFisch commented 1 year ago

I'd like to have a possibility to edit an item before it gets passed into the

.select(state=> state.data['myItemId']).subscribe(myItem => {})

callback function after I selected it from the store. Is there a way to see what items are currently subscribed too? Or is there a way hook into 'subscribe' to edit 'myItem' I subscribed to before it get's passed into my subscribe callback?

spierala commented 1 year ago

Normally the select callback is the place to transform selected data.

In your example callback state=> state.data['myItemId'], you are already transforming state to something else.

You can further transform in the select:

store.select(state => {
    const myItemId = state.data['myItemId'];
    return 'prefix_' + myItemId; // Map to whatever you want
}).subscribe(prefixedItemId => console.log(prefixedItemId)) // subscribe will get the mapped value

FYI select uses RxJS map internally. Therefore select is the preferred place to map your data.

theSilverFisch commented 1 year ago

I would like to update all items by the same function when they get selected. I need to identify dataItems which are subscribed too by setting them a new attribute containing a timestamp from the moment they got subscribed to so that another script can act as a garbage collector to remove currently unused items from the store -> the minirx store contains a "data" store which acts as a cache for our dataItems which are stored in the indexDB of the browser to prevent performance issues when having >30k dataItems

Would you know a good place to implement this genericly without having to call that timestamp function in each .select I use in my application? And wouldn't I have to send another store dispatch in the select to actually change attributes of the item for all future subscriber functions as well?

Regards

spierala commented 1 year ago

The select method is meant for reading state.

If you would try to update properties of the state or in the subscribe callback, that would mean mutating the state. One of the fundamental rules of the MiniRx Store is to use immutable data. Ideally you should use the Immutable extension to prevent mutations.

Changing properties in the state should be done ONLY by dispatching an Action and runninng the reducers.

Currently in MiniRx, there is no build in way to detect which data of the store is actually subscribed to.

Can you maybe try another approach? Maybe just load the data from the indexDB into the Store which is really needed. That sounds easier than cleaning up the unused data later.

In theory you could also wrap the store.select function for the repetitive work:

selectAndTrackSubscription(mapFn) {
     return store.select(mapFn).pipe(
         tap(selectedData => {
             // Store somewhere the subscribed data id (better in another feature, to prevent endless loop)
             store.dispatch(trackNewSubscription(selectedData.id))
         })
     );
}

I think that tap even supports subscribe and unsubscribe callbacks: https://rxjs.dev/api/index/interface/TapObserver

Or you could create a custom RxJS operator which does tap and the store dispatch.

Lets say you created a selectAndTrackSubscription operator. Then you could do this:

store.select().pipe(selectAndTrackSubscription);
spierala commented 1 year ago

@theSilverFisch, did one of the solutions work?

Can I close this issue?