J'ai un composant nommé "Item" qui crée et appelle une promesse quand il a été monté.
class Item extends React.Component{
constructor(props){
super(props)
this.onClick = this.onClick.bind(this)
this.prom = new Promise((resolve, reject) => {
setTimeout(() => resolve("PROMISE COMPLETED "+this.props.id),6000)
})
}
componentDidMount(){
this.prom.then((success) => {
console.log(success)
})
}
componentWillUnmount(){
console.log("unmounted")
}
onClick(e){
e.preventDefault()
this.props.remove(this.props.id)
}
render(){
return (
<h1>Item {this.props.id} - <a href="#" onClick={this.onClick}>Remove</a></h1>
)
}
}
Comme vous pouvez le voir, la promesse appelle la résolution 6 secondes après son appel.
Il existe un autre composant nommé "Liste" qui est chargé d'afficher ces éléments à l'écran. La "Liste" est le parent du composant "Article".
class List extends React.Component{
constructor(props){
super(props)
this.state = {
items : [1,2,3]
}
this.handleRemove = this.handleRemove.bind(this)
}
handleRemove(id){
this.setState((prevState, props) => ({
items : prevState.items.filter((cId) => cId != id)
}));
}
render(){
return (
<div>
{this.state.items.map((item) => (
<Item key={item} id={item} remove={this.handleRemove} />
))
}
</div>
)
}
}
ReactDOM.render(<List />,root)
Dans l'exemple ci-dessus, il montre trois éléments à l'écran.
Si je supprime l'un de ces composants, componentWillUnmount () est appelé mais également la promesse qui a été créée dans le composant supprimé est exécutée.
Par exemple, je peux voir que la promesse du deuxième élément est exécutée même si je supprime le deuxième élément.
unmounted
PROMISE COMPLETED 1
PROMISE COMPLETED 2
PROMISE COMPLETED 3
Je dois annuler la promesse lorsqu'un composant est démonté.
Une variation de cela https://hshno.de/BJ46Xb_r7 semblait fonctionner pour moi. J'ai créé un HOC avec la variable d'instance mounted
et j'ai encapsulé tous les composants asynchrones.
Voici à quoi ressemble mon code.
export function makeMountAware(Component) {
return class MountAwareComponent extends React.Component {
mounted = false;
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
return (
<Component
mounted = {this.mounted}
{...this.props}
{...this.state}
/>
);
}
}
class AsyncComponent extends React.Component {
componentDidMount() {
fetchAsyncData()
.then(data => {
this.props.mounted && this.setState(prevState => ({
...prevState,
data
}));
});
}
}
export default makeMountAware(AsyncComponent);
Vous ne pouvez pas annuler les promesses natives d'ES6. En savoir plus sur https://medium.com/@benlesh/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082
Cependant, vous pouvez peut-être utiliser des bibliothèques de promesses non natives comme Bluebird ou Q , qui vous donnent des promesses qui peuvent être annulé.
Vous pouvez faire différentes choses. Le plus simple est de reject
la promesse:
this.prom = new Promise((resolve, reject) => {
this.rejectProm = reject;
...
});
puis
componentWillUnmount(){
if (this.rejectProm) {
this.rejectProm();
this.rejectProm = nil;
}
console.log("unmounted")
}
Étant donné que vous utilisez un délai d'expiration dans cet exemple, vous devez le supprimer lors du démontage.
class Item extends React.Component{
constructor(props){
super(props)
this.onClick = this.onClick.bind(this)
// attribute for the timeout
this.timeout = null;
this.prom = new Promise((resolve, reject) => {
// assign timeout
this.timeout = setTimeout(() => resolve("PROMISE COMPLETED "+this.props.id),6000)
})
}
componentDidMount(){
this.prom.then((success) => {
console.log(success)
})
}
componentWillUnmount(){
// clear timeout
clearTimeout(this.timeout);
console.log("unmounted")
}
Je suppose que cela entraînera un rejet et vous ne verrez pas ce journal de console.