Using CPromise package, you can cancel your promise chains, including nested ones. It supports AbortController and generators as a replacement for ECMA async functions. Using CPromise decorators, you can easily manage your async tasks, making them cancellable.
Decorators usage Live Demo :
import React from "react";
import { ReactComponent, timeout } from "c-promise2";
import cpFetch from "cp-fetch";
@ReactComponent
class TestComponent extends React.Component {
state = {
text: "fetching..."
};
@timeout(5000)
*componentDidMount() {
console.log("mounted");
const response = yield cpFetch(this.props.url);
this.setState({ text: `json: ${yield response.text()}` });
}
render() {
return <div>{this.state.text}</div>;
}
componentWillUnmount() {
console.log("unmounted");
}
}
All stages there are completely cancelable/abortable.
Here is an example of using it with React Live Demo
import React, { Component } from "react";
import {
CPromise,
CanceledError,
ReactComponent,
E_REASON_UNMOUNTED,
listen,
cancel
} from "c-promise2";
import cpAxios from "cp-axios";
@ReactComponent
class TestComponent extends Component {
state = {
text: ""
};
*componentDidMount(scope) {
console.log("mount");
scope.onCancel((err) => console.log(`Cancel: ${err}`));
yield CPromise.delay(3000);
}
@listen
*fetch() {
this.setState({ text: "fetching..." });
try {
const response = yield cpAxios(this.props.url).timeout(
this.props.timeout
);
this.setState({ text: JSON.stringify(response.data, null, 2) });
} catch (err) {
CanceledError.rethrow(err, E_REASON_UNMOUNTED);
this.setState({ text: err.toString() });
}
}
*componentWillUnmount() {
console.log("unmount");
}
render() {
return (
<div className="component">
<div className="caption">useAsyncEffect demo:</div>
<div>{this.state.text}</div>
<button
className="btn btn-success"
type="submit"
onClick={() => this.fetch(Math.round(Math.random() * 200))}
>
Fetch random character info
</button>
<button
className="btn btn-warning"
onClick={() => cancel.call(this, "oops!")}
>
Cancel request
</button>
</div>
);
}
}
Using Hooks and cancel
method
import React, { useState } from "react";
import {
useAsyncEffect,
E_REASON_UNMOUNTED,
CanceledError
} from "use-async-effect2";
import cpAxios from "cp-axios";
export default function TestComponent(props) {
const [text, setText] = useState("");
const [id, setId] = useState(1);
const cancel = useAsyncEffect(
function* () {
setText("fetching...");
try {
const response = yield cpAxios(
`https://rickandmortyapi.com/api/character/${id}`
).timeout(props.timeout);
setText(JSON.stringify(response.data, null, 2));
} catch (err) {
CanceledError.rethrow(err, E_REASON_UNMOUNTED);
setText(err.toString());
}
},
[id]
);
return (
<div className="component">
<div className="caption">useAsyncEffect demo:</div>
<div>{text}</div>
<button
className="btn btn-success"
type="submit"
onClick={() => setId(Math.round(Math.random() * 200))}
>
Fetch random character info
</button>
<button className="btn btn-warning" onClick={cancel}>
Cancel request
</button>
</div>
);
}