183 votes

Mise à jour du composant React toutes les secondes

Je me suis amusé avec React et j'ai le composant temporel suivant qui ne fait qu'effectuer un rendu Date.now() à l'écran :

import React, { Component } from 'react';

class TimeComponent extends Component {
  constructor(props){
    super(props);
    this.state = { time: Date.now() };
  }
  render(){
    return(
      <div> { this.state.time } </div>
    );
  }
  componentDidMount() {
    console.log("TimeComponent Mounted...")
  }
}

export default TimeComponent;

Quel serait le meilleur moyen de faire en sorte que ce composant se mette à jour toutes les secondes pour redessiner l'heure du point de vue de React ?

215voto

Waiski Points 2895

Vous devez utiliser setInterval pour déclencher le changement, mais vous devez également effacer le temporisateur lorsque le composant se démonte pour éviter qu'il ne laisse des erreurs et ne laisse fuir de la mémoire :

componentDidMount() {
  this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000);
}
componentWillUnmount() {
  clearInterval(this.interval);
}

3 votes

Si vous souhaitez une bibliothèque qui encapsule ce genre de choses, j'ai créé react-interval-rerender

0 votes

J'ai ajouté la méthode setInterval dans mon constructeur et cela a mieux fonctionné.

95voto

Alireza Valizade Points 1877

Le code suivant est un exemple modifié du site web React.js.

Le code original est disponible ici : https://reactjs.org/#a-simple-component

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      seconds: parseInt(props.startTimeInSeconds, 10) || 0
    };
  }

  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }

  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

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

  formatTime(secs) {
    let hours   = Math.floor(secs / 3600);
    let minutes = Math.floor(secs / 60) % 60;
    let seconds = secs % 60;
    return [hours, minutes, seconds]
        .map(v => ('' + v).padStart(2, '0'))
        .filter((v,i) => v !== '00' || i > 0)
        .join(':');
  }

  render() {
    return (
      <div>
        Timer: {this.formatTime(this.state.seconds)}
      </div>
    );
  }
}

ReactDOM.render(
  <Timer startTimeInSeconds="300" />,
  document.getElementById('timer-example')
);

1 votes

Pour une raison quelconque, j'obtiens l'erreur this.updater.enqueueSetState is not a function lorsque j'utilise cette approche. Le callback setInterval est correctement lié au composant this.

29 votes

Pour les idiots comme moi : ne pas nommer le timer. updater parce que cela ruine le cycle de mise à jour

3 votes

Avec ES6, je dois modifier une ligne comme this.interval = setInterval(this.tick.bind(this),1000) ;

9voto

erik-sn Points 1420

Dans la section du composant componentDidMount vous pouvez définir un intervalle pour appeler une fonction qui met à jour l'état.

 componentDidMount() {
      setInterval(() => this.setState({ time: Date.now()}), 1000)
 }

4 votes

Correct, mais comme le suggère la première réponse, n'oubliez pas d'effacer le temps pour éviter les fuites de mémoire : componentWillUnmount() { clearInterval(this.interval) ; }

5voto

Jagadeesh Points 59
class ShowDateTime extends React.Component {
   constructor() {
      super();
      this.state = {
        curTime : null
      }
    }
    componentDidMount() {
      setInterval( () => {
        this.setState({
          curTime : new Date().toLocaleString()
        })
      },1000)
    }
   render() {
        return(
          <div>
            <h2>{this.state.curTime}</h2>
          </div>
        );
      }
    }

0voto

Daniel Points 1346

Donc vous étiez sur la bonne voie. Dans votre componentDidMount() vous auriez pu terminer le travail en mettant en œuvre setInterval() pour déclencher le changement, mais rappelez-vous que la façon de mettre à jour l'état d'un composant est via setState() donc dans votre componentDidMount() vous auriez pu faire ça :

componentDidMount() {
  setInterval(() => {
   this.setState({time: Date.now()})    
  }, 1000)
}

Aussi, vous utilisez Date.now() qui fonctionne, avec le componentDidMount() que j'ai proposée ci-dessus, mais vous obtiendrez un long ensemble de chiffres désagréables qui ne sont pas lisibles par l'homme, mais il s'agit techniquement de l'heure mise à jour chaque seconde en millisecondes depuis le 1er janvier 1970. setInterval vous voulez en savoir plus sur new Date() y toLocaleTimeString() et vous l'implémenteriez comme suit :

class TimeComponent extends Component {
  state = { time: new Date().toLocaleTimeString() };
}

componentDidMount() {
  setInterval(() => {
   this.setState({ time: new Date().toLocaleTimeString() })    
  }, 1000)
}

Remarquez que j'ai également retiré le constructor() vous n'en avez pas forcément besoin, mon refactor est 100% équivalent à initialiser le site avec la fonction constructor() fonction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X