grafana/public/app/core/services/StateManagerBase.ts
Torkel Ödegaard 915ebcf832
Search: Refactor state and logic to be less fragmented and spread out (#57973)
* Started search state refactor

* Things are working

* Move more to statemanger

* minor tweaks

* Fixed name of hook

* revert yarn.lock changes

* Harderning StateManagerBase

* More tests and refinements

* Fixed unit test

* More polish

* fixing tests

* fixed test

* Fixed test
2022-11-03 08:29:39 +01:00

52 lines
1.3 KiB
TypeScript

import { useEffect } from 'react';
import { Observer, Subject, Subscription } from 'rxjs';
import { useForceUpdate } from '@grafana/ui';
export class StateManagerBase<TState> {
private _subject = new Subject<TState>();
private _state: TState;
constructor(state: TState) {
this._state = state;
}
useState() {
// eslint-disable-next-line react-hooks/rules-of-hooks
return useLatestState(this);
}
get state() {
return this._state;
}
setState(update: Partial<TState>) {
this._state = {
...this._state,
...update,
};
this._subject.next(this._state);
}
/**
* Subscribe to the scene state subject
**/
subscribeToState(observerOrNext?: Partial<Observer<TState>>): Subscription {
return this._subject.subscribe(observerOrNext);
}
}
/**
* This hook is always returning model.state instead of a useState that remembers the last state emitted on the subject
* The reason for this is so that if the model instance change this function will always return the latest state.
*/
function useLatestState<TState>(model: StateManagerBase<TState>): TState {
const forceUpdate = useForceUpdate();
useEffect(() => {
const s = model.subscribeToState({ next: forceUpdate });
return () => s.unsubscribe();
}, [model, forceUpdate]);
return model.state;
}