web-dev-qa-db-fra.com

Annuler tous les abonnements et les codes asynchrones dans la méthode ComponentWillUnmount, comment?

Je reçois un message d'erreur en raison d'un problème de méthode asynchrone. Je vois dans mon terminal:

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
- node_modules/fbjs/lib/warning.js:33:20 in printWarning
- node_modules/fbjs/lib/warning.js:57:25 in warning
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:12196:6 in warnAboutUpdateOnUnmounted
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:13273:41 in scheduleWorkImpl
- node_modules/react-native/Libraries/Renderer/ReactNativeRenderer-dev.js:6224:19 in enqueueSetState
- node_modules/react/cjs/react.development.js:242:31 in setState
* router/_components/item.js:51:16 in getImage$
- node_modules/regenerator-runtime/runtime.js:62:44 in tryCatch
- node_modules/regenerator-runtime/runtime.js:296:30 in invoke
- ... 13 more stack frames from framework internals

J'ai remarqué que cela indiquait spécifiquement le getImage$

Voici le code que j'utilise pour cette section:

export default class extends Component {
    constructor(props) {
        super(props);
        const { item } = props

        const bindThese = { item }
        this.boundActionCreators = bindActionCreators(bindThese)

        this.state = {
            image: require('../../static/logo.png'),
            ready: false,
            showOptions: this.props.showOptions
        }

        this.getImage = this.getImage.bind(this)
        this.renderNotAdmin = this.renderNotAdmin.bind(this)
        this.renderAdmin = this.renderAdmin.bind(this)
        this.handleOutOfStock = this.handleOutOfStock.bind(this)
    }

    async getImage(img) {
        let imgUri = await Amplify.Storage.get(img)
        let uri = await CacheManager.get(imgUri).getPath()

        this.setState({
            image: { uri },
            ready: true
        })
    }

    componentDidMount() {
        this.getImage(this.props.item.image)
    }

J'essaie de comprendre comment utiliser un componentWillUnmount avec cette méthode asynchrone. Comment je m'y prends?

Merci!

16
Dres

Vous pouvez utiliser le motif isMounted React pour éviter les fuites de mémoire ici.

Dans votre constructeur:

constructor(props) {
    super(props);

    this._isMounted = false;
// rest of your code
}

componentDidMount() {
    this._isMounted = true;
    this._isMounted && this.getImage(this.props.item.image);

}

dans votre componentWillUnmount

componentWillUnmount() {
   this._isMounted = false;
}

En toi getImage()

async getImage(img) {
    let imgUri = await Amplify.Storage.get(img)
    let uri = await CacheManager.get(imgUri).getPath()

    this._isMounted && this.setState({
        image: { uri },
        ready: true
    })
}

Une approche recommandée pour utiliser Axios qui repose sur un modèle de promesse annulable. Ainsi, vous pouvez annuler tout appel réseau tout en démontant le composant avec son cancelToken subscription. Voici une ressource pour Annulation Axios

33
Sakhi Mansoor

De la blog React

Définissez simplement une propriété _isMounted sur true dans composantDidMount et définissez-la sur false dans composantWillUnmount. Utilisez cette variable pour vérifier le statut de votre composant.

On ajoute qu'idéalement, le problème pourrait être résolu en utilisant des rappels annulables, bien que la première solution semble appropriée ici.

Ce que vous ne devriez absolument pas faire est d’utiliser la fonction isMounted (), qui peut être obsolète.

5
Keir Lewis

Vous devez définir this.mounted = false dans la méthode ComponentWillUnmount () et this.mounted = true dans la méthode ComponentDidMount ().

La mise à jour de setState est conditionnelle en fonction de la nécessité de déclarer dans la méthode composantDidMount ().

componentDidMount() {
        this.mounted = true;
        var myVar =  setInterval(() => {
                let nextPercent = this.state.percentage+10;
                if (nextPercent >= 100) {
                    clearInterval(myVar);
                }
                if(this.mounted) {
                    this.setState({ percentage: nextPercent });
            }
        }, 100);
}

componentWillUnmount(){
      this.mounted = false;
}
4
KARTHIKEYAN.A