-
Notifications
You must be signed in to change notification settings - Fork 2
Using with React
DigitalBrainJS edited this page Oct 17, 2021
·
1 revision
With CPromise decorators, a generic React class component that fetches JSON might look like the following:
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);
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 some specific decorators we can control our async flow in a declarative way: Live Demo
import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles.css";
import { async, listen, cancel, timeout } from "c-promise2";
import cpFetch from "cp-fetch";
export class TestComponent extends React.Component {
state = {
text: ""
};
@timeout(5000)
@listen
@async
*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>;
}
@cancel()
componentWillUnmount() {
console.log("unmounted");
}
}
It automatically manages async code i.g request, so it protects from warning appearing like:
Warning: Can’t perform a React state update on an unmounted component.
If you prefer functional components you can use use-async-effect2
package that decorates CPromise
into custom React hooks - useAsyncEffect
and useAsyncCallback
:
import React from "react";
import {useState} from "react";
import {useAsyncEffect} from "use-async-effect2";
import cpFetch from "cp-fetch";
function FetchComponent(props) {
const [text, setText] = useState("");
const cancel= useAsyncEffect(function* () {
setText("fetching...");
const response = yield cpFetch(props.url); // will throw a CanceledError if component get unmounted
const json = yield response.json();
setText(`Success: ${JSON.stringify(json)}`);
}, [props.url]);
return (
<div>
<span>{text}</span>
<button onClick={cancel}>Cancel request</button>
</div>
);
}