web-dev-qa-db-fra.com

setInterval dans une application React

Je suis encore assez nouveau chez React, mais j'ai progressé lentement et j'ai rencontré quelque chose sur lequel je suis coincé.

J'essaie de créer un composant "timer" dans React, et pour tout vous dire, je ne sais pas si je le fais correctement (ou efficacement). Dans mon code ci-dessous, j'ai défini l'état pour retourner un objet { currentCount: 10 } et j'ai joué avec componentDidMount, componentWillUnmount et render et je ne peux obtenir que l'état " compte à rebours "de 10 à 9.

Question en deux parties: Qu'est-ce qui ne va pas? Et existe-t-il un moyen plus efficace d'utiliser setTimeout (plutôt que componentDidMount & componentWillUnmount)?

Merci d'avance.

import React from 'react';

var Clock = React.createClass({

  getInitialState: function() {
    return { currentCount: 10 };
  },

  componentDidMount: function() {
    this.countdown = setInterval(this.timer, 1000);
  },

  componentWillUnmount: function() {
    clearInterval(this.countdown);
  },

  timer: function() {
    this.setState({ currentCount: 10 });
  },

  render: function() {
    var displayCount = this.state.currentCount--;
    return (
      <section>
        {displayCount}
      </section>
    );
  }

});

module.exports = Clock;
83
Jose

Je vois 4 problèmes avec votre code:

  • Dans votre méthode de minuterie, vous définissez toujours votre compte actuel sur 10
  • Vous essayez de mettre à jour l'état dans la méthode de rendu
  • Vous n'utilisez pas la méthode setState pour réellement changer l'état
  • Vous ne stockez pas votre intervalleId dans l'état

Essayons de résoudre ce problème:

componentDidMount: function() {
   var intervalId = setInterval(this.timer, 1000);
   // store intervalId in the state so it can be accessed later:
   this.setState({intervalId: intervalId});
},

componentWillUnmount: function() {
   // use intervalId from the state to clear the interval
   clearInterval(this.state.intervalId);
},

timer: function() {
   // setState method is used to update the state
   this.setState({ currentCount: this.state.currentCount -1 });
},

render: function() {
    // You do not need to decrease the value here
    return (
      <section>
       {this.state.currentCount}
      </section>
    );
}

Cela entraînerait une minuterie qui passe de 10 à -N. Si vous voulez une minuterie qui diminue à 0, vous pouvez utiliser une version légèrement modifiée:

timer: function() {
   var newCount = this.state.currentCount - 1;
   if(newCount >= 0) { 
       this.setState({ currentCount: newCount });
   } else {
       clearInterval(this.state.intervalId);
   }
},
139
dotnetom

Compte à rebours de 10 secondes mis à jour avec class Clock extends Component

import React, { Component } from 'react';

class Clock extends Component {
  constructor(props){
    super(props);
    this.state = {currentCount: 10}
  }
  timer() {
    this.setState({
      currentCount: this.state.currentCount - 1
    })
    if(this.state.currentCount < 1) { 
      clearInterval(this.intervalId);
    }
  }
  componentDidMount() {
    this.intervalId = setInterval(this.timer.bind(this), 1000);
  }
  componentWillUnmount(){
    clearInterval(this.intervalId);
  }
  render() {
    return(
      <div>{this.state.currentCount}</div>
    );
  }
}

module.exports = Clock;
28
Greg Herbowicz

Compte à rebours de 10 secondes mis à jour à l'aide de crochets (nouvelle proposition de fonctionnalité vous permettant d'utiliser l'état et d'autres fonctionnalités React sans écrire de classe. Elles sont actuellement dans React v16.7.0-alpha).

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';

const Clock = () => {
    const [currentCount, setCount] = useState(10);
    const timer = () => setCount(currentCount - 1);

    useEffect(
        () => {
            if (currentCount <= 0) {
                return;
            }
            const id = setInterval(timer, 1000);
            return () => clearInterval(id);
        },
        [currentCount]
    );

    return <div>{currentCount}</div>;
};

const App = () => <Clock />;

ReactDOM.render(<App />, document.getElementById('root'));
12
Greg Herbowicz

Merci @dotnetom, @ greg-herbowicz

S'il renvoie "this.state is undefined" - fonction de minuterie de liaison:

constructor(props){
    super(props);
    this.state = {currentCount: 10}
    this.timer = this.timer.bind(this)
}
0
tulsluper