2016-08-30 1 views
0

Ich habe einen Countdown-Timer in einer React-Komponente, die für 10 Sekunden zählt. Wenn innerhalb dieser 10 Sekunden die Komponente Backend-Daten empfängt, wird der Timer gestoppt. Ist dies nicht der Fall, wird auf 0 heruntergezählt. An diesem Punkt wird die Seite aktualisiert und erneut gezählt usw., bis die Daten empfangen werden. Mein Code ist unten angegeben:setInterval Timer funktioniert nicht richtig in render() von ReactJS

constructor() { 
    ... 
    this.counter = 10; 
    ... 
} 

render() { 
    const interval = setInterval(() => { 
     const result = this.state.data; 
     if (result) { 
      this.setState({ 
       resultsReceived: true 
      }); 
      clearInterval(interval); 
     } else { 
      this.setState({ 
       resultsReceived: false 
      }); 

      this.counter = this.counter - 1; 
      if (this.counter === 0) { 
       window.location.reload(); 
      } 
     } 
    }, 1000); 

Das Problem ist, der Timer scheint nicht jede Sekunde dekrementieren. Stattdessen ist das Verhalten unberechenbar - von 10 bis vielleicht 7 ist es sehr schnell, dann kann es hängen oder sogar nach 0 weitergehen, d. H. Negativ. Die Seite wird neu geladen. Ist dieser Code falsch oder handelt es sich um ein Problem im Zusammenhang mit dem Status von React? Jede Hilfe wäre großartig!

UPDATE:

ich den Code auf diese geändert:

constructor() { 
    this.state = { 
     ... 
     interval: '', 
     counter: 10 
    }; 
} 

componentWillMount() { 
    $.ajax({ 
     url: this.props.api, 
     datatype: 'json', 
     cache: false, 
     success: (data) => { 
      this.setState({ data }); 
     } 
    }); 
    const interval = setInterval(() => { 
     const results = this.state.data; 
     if (results) { 
      this.setState({ 
       resultsReceived: true 
      }); 
      clearInterval(this.state.interval); 
     } else { 
      this.setState({ 
       resultsReceived: false 
      }); 
      let counter; 
      counter = this.state.counter - 1; 
      this.setState({ counter }); 
      if (this.state.counter === 0) { 
       window.location.reload(); 
      } 
     } 
    }, 1000); 
    this.setState({ interval }); 
} 

componentWillUnmount() { 
    clearInterval(this.state.interval); 
} 

Es ist besser als vorher, dass in der Timer richtig beim ersten Mal funktioniert - es geht 10-0 jede 1 Sekunde. Wenn die Daten jedoch auch nach 10 Sekunden noch nicht geladen sind und der Timer wieder bei 10 beginnt, erreicht er 9 und stoppt dann, bis die Daten schließlich geladen werden. Die Seite wird auch sehr langsam.

+0

Ich empfehle Ihnen, diese https zu lesen: http://facebook.github.io/react/docs/component-specs.html Sie suchen nach * componentWillMount * und * componentWillUnmount * –

+0

Sind Sie sicher, dass Sie nicht zahlreiche neue Intervall beginnen Timer, indem Sie den Code in die render() -Funktion setzen? Rectjs sind mir nicht vertraut, aber render() wird in der Regel mehrmals pro Sekunde aufgerufen. –

+0

@AntonBanchev möglicherweise. Ich versuche, sie jetzt in componentWillMount und componentWillUnmount zu verwenden, wie Jesús Quintana sagte – user3033194

Antwort

1

Ich bin nicht sicher, warum das passiert, aber ich bin sicher, dass Ihr Code etwas sehr seltsam ist.

  1. Zunächst einmal ist es sehr seltsam, Ihr Intervall auf state zu halten. Bewahren Sie es stattdessen in Ihrer Komponenteninstanz auf, damit Sie es problemlos löschen können.

  2. Legen Sie keine Daten fest und überprüfen Sie sie im Intervall. Sie können das Intervall freigeben, wenn Ihre API-Anforderung abgeschlossen ist, und die Daten in den Zustand versetzen.

  3. Das Intervall immer löschen, bevor die Komponente verworfen wird.

Das ist, was ich vorschlagen kann.

constructor() { 
    ... 
    this.interval = null 
    this.state = { counter: 10 } 
    ... 
} 

componentWillMount() { 
    $.ajax({ 
    url: this.props.api, 
    datatype: 'json', 
    cache: false, 
    success: (data) => { 
     this.setState({ data }) 
     clearInterval(this.interval); 
    }, 
    }); 

    this.interval = setInterval(() => { 
    if (counter <= 0) { 
     clearInterval(this.interval); 
     location.reload(); 
     return; 
    } 

    this.setState({ 
     counter: this.state.counter - 1, 
    }); 
    }, 1000); 
} 

componentWillUnmount() { 
    clearInterval(this.interval) 
} 

eigentlich, wenn Sie nicht Intervall verwenden und SetTimeout es wäre viel besser, wenn Ihre state.counter nur existiert, um zu überprüfen, wie viele Sekunden vergangen ist.

constructor() { 
    ... 
    this.timeout = null 
    ... 
} 

componentWillMount() { 
    $.ajax({ 
    url: this.props.api, 
    datatype: 'json', 
    cache: false, 
    success: (data) => { 
     this.setState({ data }) 
     clearTimeout(this.timeout); 
    } 
    }); 

    this.timeout = setTimeout(() => { 
    clearTimeout(this.timeout); 
    location.reload(); 
    }, 1000 * 10); 
} 

componentWillUnmount() { 
    clearTimeout(this.timeout) 
} 

setInterval ist teuer. Benutze es nicht für diese Art von Arbeit.

+0

Danke! Das hat funktioniert. Tatsächlich habe ich Ihre erste Lösung verwendet, weil ich den Zählerwert anzeigen muss, wenn er jede Sekunde dekrementiert. Aber ich habe auch deine zweite Lösung verstanden. Ich habe setInterval nicht zuvor mit React verwendet, also habe ich von Ihren Lösungen gelernt – user3033194