fromPromise

fromPromise takes a Promise, extends it with 2 observable properties that track the status of the promise and returns it. The returned object has the following observable properties:

  • value: either the initial value, the value the Promise resolved to, or the value the Promise was rejected with. use .state if you need to be able to tell the difference.
  • state: one of "pending", "fulfilled" or "rejected"

And the following methods:

  • case({fulfilled, rejected, pending}): maps over the result using the provided handlers, or returns undefined if a handler isn’t available for the current promise state.
  • then((value: TValue) => TResult1 | PromiseLike<TResult1>, [(rejectReason: any) => any]): chains additional handlers to the provided promise.

The returned object implements PromiseLike<TValue>, so you can chain additional Promise handlers using then. You may also use it with await in async functions.

Note that the status strings are available as constants: mobxUtils.PENDING, mobxUtils.REJECTED, mobxUtil.FULFILLED

fromPromise takes an optional second argument, a previously created fromPromise based observable. This is useful to replace one promise based observable with another, without going back to an intermediate “pending” promise state while fetching data. For example:

Parameters

  • promise IThenable<T> The promise which will be observed
  • oldPromise IThenable<T> ? The promise which will be observed

Examples

  1. @observer
  2. class SearchResults extends React.Component {
  3. @observable searchResults
  4. componentDidUpdate(nextProps) {
  5. if (nextProps.query !== this.props.query)
  6. this.comments = fromPromise(
  7. window.fetch("/search?q=" + nextProps.query),
  8. // by passing, we won't render a pending state if we had a successful search query before
  9. // rather, we will keep showing the previous search results, until the new promise resolves (or rejects)
  10. this.searchResults
  11. )
  12. }
  13. render() {
  14. return this.searchResults.case({
  15. pending: (staleValue) => {
  16. return staleValue || "searching" // <- value might set to previous results while the promise is still pending
  17. },
  18. fulfilled: (value) => {
  19. return value // the fresh results
  20. },
  21. rejected: (error) => {
  22. return "Oops: " + error
  23. }
  24. })
  25. }
  26. }
  27. Observable promises can be created immediately in a certain state using
  28. `fromPromise.reject(reason)` or `fromPromise.resolve(value?)`.
  29. The main advantage of `fromPromise.resolve(value)` over `fromPromise(Promise.resolve(value))` is that the first _synchronously_ starts in the desired state.
  30. It is possible to directly create a promise using a resolve, reject function:
  31. `fromPromise((resolve, reject) => setTimeout(() => resolve(true), 1000))`
  1. const fetchResult = fromPromise(fetch("http://someurl"))
  2. // combine with when..
  3. when(
  4. () => fetchResult.state !== "pending",
  5. () => {
  6. console.log("Got ", fetchResult.value)
  7. }
  8. )
  9. // or a mobx-react component..
  10. const myComponent = observer(({ fetchResult }) => {
  11. switch(fetchResult.state) {
  12. case "pending": return <div>Loading...</div>
  13. case "rejected": return <div>Ooops... {fetchResult.value}</div>
  14. case "fulfilled": return <div>Gotcha: {fetchResult.value}</div>
  15. }
  16. })
  17. // or using the case method instead of switch:
  18. const myComponent = observer(({ fetchResult }) =>
  19. fetchResult.case({
  20. pending: () => <div>Loading...</div>,
  21. rejected: error => <div>Ooops.. {error}</div>,
  22. fulfilled: value => <div>Gotcha: {value}</div>,
  23. }))
  24. // chain additional handler(s) to the resolve/reject:
  25. fetchResult.then(
  26. (result) => doSomeTransformation(result),
  27. (rejectReason) => console.error('fetchResult was rejected, reason: ' + rejectReason)
  28. ).then(
  29. (transformedResult) => console.log('transformed fetchResult: ' + transformedResult)
  30. )

Returns IPromiseBasedObservable<T>