Skip to content

Instantly share code, notes, and snippets.

@hediet
Created April 3, 2020 12:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hediet/2c00c926bfdf8cdeffb775b78acc20ae to your computer and use it in GitHub Desktop.
Save hediet/2c00c926bfdf8cdeffb775b78acc20ae to your computer and use it in GitHub Desktop.
Mobx Complex Observable Example
type State = { kind: 'loading' } | { kind: 'loaded'; service: unknown };
@injectable()
class LoadServiceModel {
constructor(
@injectProps()
private readonly props: {
service: ServiceId<unknown>;
module?: Module;
},
@inject($ModuleService)
private readonly moduleService: typeof $ModuleService.T,
@inject($K3Container)
private readonly k3Container: typeof $K3Container.T
) {}
/**
* The loader is cached by mobx and recreated whenever something changes
* that the loader depends on.
* The loader has an inner state that reflects its progress.
*/
@computed
private get loader(): { state: State } {
const result = observable<{ state: State }>({
state: { kind: 'loading' },
});
const p = this.props.module
? this.moduleService.loadModule(this.props.module)
: this.moduleService.loadModuleThatProvidesService(
this.props.service
);
p.then(() => {
runInAction('Update loading state', () => {
const service = this.k3Container.getService(this.props.service);
result.state = { kind: 'loaded', service };
});
});
return result;
}
public get state(): State {
return this.loader.state;
}
}
@injectable()
class LoadServiceModel {
@observable state:
| { kind: 'loading' }
| { kind: 'loaded'; service: unknown } = { kind: 'loading' };
constructor(
@injectProps()
props: {
service: ServiceId<unknown>;
module?: Module;
},
@inject($ModuleService) moduleService: typeof $ModuleService.T,
@inject($K3Container) k3Container: typeof $K3Container.T
) {
// Problem 1: This is not rerun when dependencies change!
// Problem 2: Autorun is asynchronous, the render reaction may run before it!
const p = props.module
? moduleService.loadModule(props.module)
: moduleService.loadModuleThatProvidesService(props.service);
p.then(() => {
runInAction('Update loading state', () => {
const service = k3Container.getService(props.service);
this.state = { kind: 'loaded', service };
});
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment