Decorator for automatically canceling observable and other subscriptions when a React component is unmounted.
A cancelWhenUnmounted
function is passed to the decorated component as a prop,
which should be called with an observable subscription (a disposable). Click here
for more documentation on canceling observables.
Also, a cancelAllSubscriptions
function is passed to the decorated component as a prop. This should be called with
no arguments, and will cancel all subscriptions that were registered via cancelWhenUnmounted
. It will also reset the list of
subscriptions to be empty, so that future calls to cancelWhenUnmounted
and cancelAllSubscriptions
will start fresh.
Note that cancelAllSubscriptions
is automatically called during componentWillUnmount.
Finally, react-disposable-decorator uses the forwardRef
API (requires 16.3+
) so it is possible to access the original component.
npm install react-disposable-decorator
or
yarn add react-disposable-decorator
import Cancelable from 'react-disposable-decorator';
@Cancelable //decorate the component
export default class SomeComponent extends React.Component {
componentDidMount() {
this.props.cancelWhenUnmounted(
/* This will be automatically canceled if the observable does not
* onComplete or onError before the React component is unmounted.
*/
fetchSomeData.subscribe( data => this.setstate({data}) )
);
}
componentDidUpdate(prevProps) {
// Example usage of how you might use cancelAllSubscriptions
if (this.props.needToMakeNewSubscriptions) {
this.props.cancelAllSubscriptions();
this.props.cancelWhenUnmounted(
fetchSomeData.subscribe(data => this.setState({data}));
);
}
}
}
...
If you're using Enzyme shallow rendering, try doing shallow(<Foo />).dive()
on
components decorated with react-disposable-decorator to be able to test the wrapped component.
If you wish to disable the react-disposable-decorator in tests altogether (so you don't have to .dive()
), you can
set a global variable global.disableReactDisposableDecorator = true
in your test configuration before you import the
react-disposable-decorator javascript module into the test environment.
react-disposable-decorator uses react 16.3+ and the forwardRef API to ensure that your refs go to the original component and not the decorated component. Using refs to access components have good use cases listed here.
import Cancelable from 'react-disposable-decorator'
@Cancelable
class Hello extends React.Component {
constructor(props) {
super(props)
this.logHello = this.logHello.bind(this)
}
logHello() {
console.log('hello')
}
render () {
<div>
Hello
</div>
}
}
class wrappingComponent extends React.Component {
componentDidMount() {
this.hello.logHello()
// calls logHello
}
render () {
return (
<div>
<Hello ref={el => this.hello = el}>
</div>
)
}
}