2017-08-14 2 views
0

Ich habe eine funktionierende Ladekomponente, die abgebrochen wird, wenn es für 8 Sekunden geladen wurde. Dieser Code funktioniert, aber es fühlt sich für mich an und ich frage mich, ob es einen besseren Weg dafür gibt.Bessere Möglichkeit zum Löschen von Timeout in ComponentWillUnmount

Ohne this.mounted Einstellung erhalte ich die Fehlermeldung:

Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op. Please check the code for the Loading component.

Diese ich denke, dass der Timer nicht abgebrochen zu werden, so dass es mit this.seState weiter. Warum würde das sein, wenn ich clearTimeout ineinstelle? Gibt es einen besseren Weg, dies zu handhaben als mit einem globalen this.mounted?

class Loading extends Component { 
    state = { 
    error: false, 
    }; 

    componentDidMount =() => { 
    this.mounted = true; 
    this.timer(); 
    }; 

    componentWillUnmount =() => { 
    this.mounted = false; 
    clearTimeout(this.timer); 
    }; 

    timer =() => 
    setTimeout(() => { 
     (this.mounted && this.setState({ error: true })) || null; 
    }, 8000); 

    render() { 
    const { showHeader = false } = this.props; 
    const { error } = this.state; 
    return (
     <View style={backgroundStyle}> 
     {showHeader && <HeaderShell />} 
     {!error && 
      <View style={loadingHeight}> 
      <PlatformSpinner size="large" /> 
      </View>} 
     {error && <Error code="service" />} 
     </View> 
    ); 
    } 
} 

Loading.propTypes = { 
    showHeader: PropTypes.bool, 
}; 

Loading.defaultProps = { 
    showHeader: false, 
}; 

export default Loading; 
+5

Sie müssen den Wert speichern von 'setTimeout()' irgendwo zurück und übergebe das an 'clearTimeout()'. Sie übergeben diese Funktionsreferenz, die nicht funktioniert. – Pointy

+3

wie @Pointy erwähnt, müssen Sie den von setTimeout zurückgegebenen Wert speichern. Das Verwenden der 'componentWillUnmount'-Lebenszyklusmethode ist der bevorzugte Ort, um diese Operation auszuführen –

+0

Der von setTimeout zurückgegebene Wert setzt den Zustand, den ich nicht ausführen möchte, wenn ich 8 Sekunden nicht erreicht habe. – Turnipdabeets

Antwort

3

This make me think that the timer is not getting canceled

Wie gesagt Zipfel, ist es nicht. Sie übergeben eine Funktion (this.timer) in clearTimeout. Sie müssen den setTimeoutRückgabewert (das Handle des Timers) übergeben, damit Sie dieses Handle verwenden können, um es abzubrechen.

In solch einer einfachen Komponente, sehe ich nicht die Notwendigkeit für die timer Funktion, es fügt nur Komplexität hinzu; Ich habe gerade den Timer in CDM einzurichten:

class Loading extends Component { 
    state = { 
    error: false, 
    }; 

    componentDidMount =() => {    // *** 
    // Remember the timer handle    // *** 
    this.timerHandle = setTimeout(() => { // *** 
     this.setState({ error: true });  // *** 
     this.timerHandle = 0;     // *** 
    }, 8000);        // *** 
    };           // *** 
              // *** 
    componentWillUnmount =() => {    // *** 
    // Is our timer running?     // *** 
    if (this.timerHandle) {     // *** 
     // Yes, clear it      // *** 
     clearTimeout(this.timerHandle);  // *** 
     this.timerHandle = 0;    // *** 
    }          // *** 
    };           // *** 

    render() { 
    const { showHeader = false } = this.props; 
    const { error } = this.state; 
    return (
     <View style={backgroundStyle}> 
     {showHeader && <HeaderShell />} 
     {!error && 
      <View style={loadingHeight}> 
      <PlatformSpinner size="large" /> 
      </View>} 
     {error && <Error code="service" />} 
     </View> 
    ); 
    } 
} 

Loading.propTypes = { 
    showHeader: PropTypes.bool, 
}; 

Loading.defaultProps = { 
    showHeader: false, 
}; 

export default Loading; 

Aber wenn es mehr Logik ist als dargestellt, oder einfach nur persönliche Vorlieben, ja, getrennte Funktionen sind gut:

class Loading extends Component { 
    state = { 
    error: false, 
    }; 

    componentDidMount =() => { 
    this.setTimer(); 
    }; 

    componentWillUnmount =() => { 
    this.clearTimer(); 
    }; 

    setTimer =() => { 
    if (this.timerHandle) { 
     // Exception? 
     return; 
    } 
    // Remember the timer handle 
    this.timerHandle = setTimeout(() => { 
     this.setState({ error: true }); 
     this.timerHandle = 0; 
    }, 8000); 
    }; 

    clearTimer =() => { 
    // Is our timer running? 
    if (this.timerHandle) { 
     // Yes, clear it 
     clearTimeout(this.timerHandle); 
     this.timerHandle = 0; 
    } 
    }; 

    render() { 
    const { showHeader = false } = this.props; 
    const { error } = this.state; 
    return (
     <View style={backgroundStyle}> 
     {showHeader && <HeaderShell />} 
     {!error && 
      <View style={loadingHeight}> 
      <PlatformSpinner size="large" /> 
      </View>} 
     {error && <Error code="service" />} 
     </View> 
    ); 
    } 
} 

Loading.propTypes = { 
    showHeader: PropTypes.bool, 
}; 

Loading.defaultProps = { 
    showHeader: false, 
}; 

export default Loading; 
+0

Danke für das Ausschreiben. Was ist der Grund für die Einstellung auf 0? 'this.timerHandle = 0;' – Turnipdabeets

+0

@Turnipdabeets: Das mache ich immer als Flag, um anzuzeigen, dass es kein Timer-Handle mehr gibt (da '0' ein ungültiger Wert für ein Timer-Handle ist). Macht auch ein bequemes Flag (siehe die Implementierung von 'clearTimer'). Und im zweiten Codeblock, wo 'setTimer' und' clearTimer' separate Methoden sind, sollten Sie 'setTimer' einchecken. –

0

Sie müssen den Rückgabewert von setTimeout löschen verwenden (siehe unten). Aber clearTimeout in zu tun ist ein richtiger Weg, es zu tun, ich habe niemanden gesehen, der es anders macht.

componentDidMount =() => { 
    this.mounted = true; 
    this.timeout = this.timer(); 
    }; 

    componentWillUnmount =() => { 
    this.mounted = false; 
    clearTimeout(this.timeout); 
    }; 

    timer =() => 
    setTimeout(() => { 
     (this.mounted && this.setState({ error: true })) || null; 
    }, 8000); 
Verwandte Themen