Created
April 3, 2020 12:37
-
-
Save hediet/2c00c926bfdf8cdeffb775b78acc20ae to your computer and use it in GitHub Desktop.
Mobx Complex Observable Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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