Skip to content

Instantly share code, notes, and snippets.

@AlicanC
Created February 27, 2016 14:50
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 AlicanC/93631c650ea599a2f261 to your computer and use it in GitHub Desktop.
Save AlicanC/93631c650ea599a2f261 to your computer and use it in GitHub Desktop.
A legacy decorator for React components with componentDidMount methods that do asynchronous tasks
import _ from 'lodash';
export default function asyncComponentDidMount(rejector = 'Component was unmounted.') {
return (component) => {
const cancelMap = new WeakMap();
const isCancelled = async (promise) => {
let cancelled = cancelMap.get(this);
if (cancelled) return cancelled;
const result = await promise;
cancelled = cancelMap.get(this);
if (cancelled) return cancelled;
return result;
};
/* eslint-disable no-param-reassign */
component.prototype.componentDidMount = _.wrap(component.prototype.componentDidMount,
function componentDidMountWrapper(func, ...args) {
cancelMap.set(this, false);
if (typeof func === 'function') {
func.apply(this, [isCancelled, ...args]);
}
}
);
component.prototype.componentWillUnmount = _.wrap(component.prototype.componentWillUnmount,
function componentWillUnmountWrapper(func, ...args) {
let rejection;
if (typeof rejector === 'function') {
rejection = Promise.reject(rejector(this));
} else {
rejection = Promise.reject(rejector);
}
cancelMap.set(this, rejection);
if (typeof func === 'function') {
func.apply(this, args);
}
}
);
/* eslint-enable no-param-reassign */
};
}
@AlicanC
Copy link
Author

AlicanC commented Feb 27, 2016

Usage

@asyncComponentDidMount()
// or
@asyncComponentDidMount('Custom rejection message.')
// or
@asyncComponentDidMount((myComponentInstance) => {
  return 'Custom rejection message.';
})
class MyComponent extends React.Component {
  async componentDidMount(isCancelled) {
    // isCancelled() will return false until componentWillUnmount() is called and
    // it will start returning a rejected promise after it's called

    // Style 1
    const response = await doRequest();
    if (isCancelled()) return;
    this.setState({ ... }); // Your code won't reach were if cWU() was called.

    // Style 2
    const response = await doRequest();
    await isCancelled();
    this.setState({ ... }); // Your code won't reach were if cWU() was called.

    // Style 3
    const response = await isCancelled(doRequest());
    this.setState({ ... }); // Your code won't reach were if cWU() was called.
  }

  // No need to do anything in componentWillUnmount()
  // You don't even have to have a componentWillUnmount()
}

Caveats

You will get unhandled rejections.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment