问题
Context
I am using the following libraries in the relevant application: Angular 4.x, ngrx 4.x, rxjs 5.4.x
In my application I am able to get some data from a websocket but for some I have to hit a RESTful api. I am sharing the data between multiple components through ngrx. Right now I refetch the data based on events like create, update, and delete.
I don't expect much concurrent modification of the data but I do need a way to manually or automatically ensure that my client state matches the server. I would like to do optimistic updates that patch the client state rather than incurring the cost of doing a full data refresh on the relevant slice of state.
The RxJs Approach
If I wasn't using ngrx then I would probably just have a service that exposed an observable like the following that would cache the latest result of an api call and share it with all subscribes. It would update the result occasionally but only if it had subscribers.
const interval = 1000;
let counter = 0;
// setup a timer that executes immediately and on a timer
let call = Rx.Observable.timer(0, interval)
// make the fake async call
.switchMap(() => Rx.Observable.of(counter++).delay(100))
.do(x => console.log('call', x))
// cache latest value and share the value with all subscribers
.publishReplay(1, interval)
// only connect (aka make the call) if there are more than 1 subscribers
.refCount();
// convenience method for simulation
function subscribe(name, take) {
call.take(take).subscribe(
x => { console.log(name, x); },
null,
() => { console.log(`${name} completed`) }
);
}
// observers
subscribe('first', 1);
subscribe('second', 2);
window.setTimeout(() => {
subscribe('third', 3);
}, 3500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.min.js"></script>
Problem
I'm not sure how I would mimic this same behavior with ngrx since ngrx handles the subscriptions to itself. In many ways it disconnects the subscription from the source. Here are some ideas I've mulled over:
- Maybe there is a way that I could duck punch
store.select
but then I think that I would have to define explicit relationships between effects and state that are already defined in the reducers. - I could have each page/component register what it is interested in and track subscriptions that way but that is really just duplicating the subscriptions.
- I could setup projections for each slice of state that would sit in front of ngrx and somehow trigger the related effect but that seems tricky and possibly convoluted.
- Quit my job and sell pet rocks for a living.
Question
How can I pull data on an interval to update an ngrx store only when there are active subscriptions on the related slice of data?
回答1:
I don't think I understand what's going on 100%. But I think I would do something like this:
- in my store, have some properties that track whether a piece of data is being watched (boolean)
- when a component loads that watches that data, dispatch an event setting that value to true
- use ngOnDestroy to set the value to false when the component is no longer there
- have an ngrx effect that watches if that value changes. If the value changes to true, start fetching data from the server, and when it gets a response, dispatch an event to update the data in the store, and keep doing that at a certain interval. Keep the return value of your setInterval or timer in a variable that can be accessed elsewhere, maybe as a property of the class.
- if the value changes to false, a different ngrx effect is listening for that action, will grab that variable holding the timer/interval, and clear it/unsubscribe. Might be able to compose these together with takeUntil
来源:https://stackoverflow.com/questions/47597518/ngrx-polling-to-refresh-data-when-subscribed