webentwicklung-frage-antwort-db.com.de

componentDidMount: setState (oder forceUpdate) kann für eine nicht bereitgestellte Komponente nicht aufgerufen werden

Ich hole Daten in ComponentDidMount ab und aktualisiere den Status. Die berühmte Warnung wird angezeigt:

Warnung: setState (oder forceUpdate) kann für eine nicht bereitgestellte Komponente nicht aufgerufen werden. Dies ist ein No-Op, weist jedoch auf einen Speicherverlust in Ihrer Anwendung hin. Brechen Sie zum Beheben alle Subskriptionen und asynchronen Tasks in der Methode componentWillUnmount ab.

Mein Code lautet wie folgt:

componentDidMount() {
    let self = this;

    let apiBaseUrl = Config.serverUrl;
    axios.get( apiBaseUrl + '/dataToBeFetched/' )
        .then( function(response) {
            self.setState( { data: response.data } );;
        } );
}

Was verursacht diese Warnung und wie kann man die Daten am besten abrufen und den Status aktualisieren?

5
O_k

Basierend auf einer vorherigen Antwort habe ich Folgendes getan, was gut funktioniert hat:

constructor(props) {
   this.state = {isMounted: false}
}

componentDidMount() {
    let apiBaseUrl = Config.serverUrl;
    this.setState( { isMounted: true }, () => {
        axios.get( apiBaseUrl + '/dataToBeFetched/' )
            .then( (response) => { // using arrow function ES6
                if( this.state.isMounted ) {
                    this.setState( { pets: response.data } );
                }
            } ).catch( error => {
                // handle error
        } )
    } );
}

componentWillUnmount() {
    this.setState( { isMounted: false } )
}

Eine andere bessere Lösung ist, die Anforderung im Unmount wie folgt abzubrechen:

constructor(props) {
    this._source = axios.CancelToken.source();
}

componentDidMount() {
    let apiBaseUrl = Config.serverUrl;
    axios.get( apiBaseUrl + '/dataToBeFetched/', { cancelToken: this._source.token } )
        .then( (response) => { // using arrow function ES6
            if( this.state.isMounted ) {
                this.setState( { pets: response.data } );
            }
        } ).catch( error => {
            // handle error
    } );
}

componentWillUnmount() {
    this._source.cancel( 'Operation canceled due component being unmounted.' )
}
6
O_k

Sie können dies versuchen:

constructor() {
    super();
    this._isMounted = false;
}

componentDidMount() {
    this._isMounted = true;
    let apiBaseUrl = Config.serverUrl;
    this.setState( { isMounted: true }, () => {
        axios.get( apiBaseUrl + '/dataToBeFetched/' )
            .then( (response) => { // using arrow function ES6
                if( this._isMounted ) {
                    this.setState( { pets: response.data } );
                }
            } ).catch( error => {
                // handle error
        } )
    } );
}

componentWillUnmount() {
    this._isMounted = false; // equals, not :
}
1
user10942985

Dies ist höchstwahrscheinlich der Fall, weil die Komponente bereits vor dem Ende des asynchronen Aufrufs abgemeldet wurde. Das heißt, Ihr Aufruf an setState im Axios-Versprechen wird aufgerufen, nachdem die Komponente bereits ausgehängt wurde, möglicherweise aufgrund einer react-router-Umleitung oder einer Statusänderung.

0
alexlod

Der Aufruf von setState auf componentWillUnmount ist die schlechteste Vorgehensweise

componentWillUnmount() {
    this.setState( { isMounted: false } ) // don't do this
}
0
Shawn Wang