React uygulamasında setInterval


107

React'te hala oldukça yeniyim, ancak yavaş yavaş ilerledim ve takılıp kaldığım bir şeyle karşılaştım.

React'te bir "zamanlayıcı" bileşeni oluşturmaya çalışıyorum ve dürüst olmak gerekirse bunu doğru (veya verimli) yapıp yapmadığımı bilmiyorum. Aşağıda benim kodda, bir nesne döndürmek için durumu belirtmek { currentCount: 10 }ve oynuyor olmuştur componentDidMount, componentWillUnmountve renderben sadece 10 ila 9'a kadar "geri sayım" devleti alabilirsiniz.

İki parçalı soru: Neyi yanlış anlıyorum? Ve setTimeout'u kullanmanın ( componentDidMount& kullanmak yerine componentWillUnmount) daha verimli bir yolu var mı?

Şimdiden teşekkür ederim.

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;

2
bind(this)artık gerekli değil, react şimdi bunu kendi başına yapıyor.
Derek Pollard

2
zamanlayıcı yönteminiz currentCount'u güncellemiyor
Bryan Chen

1
@Derek emin misin? Sadece bana ait ekleyerek çalışma var this.timer.bind(this)onu kendi üzerinde this.timer olarak iş vermedi
solucan

6
@Theworm @Derek yanılıyor, bir nevi. React.createClass (kullanımdan kaldırılmıştır) metotları class Clock extends Componentotomatik olarak bağlar , ancak otomatik olarak bağlanmaz. Bağlamanız gerekip gerekmediği bileşenlerinizi nasıl oluşturduğunuza bağlıdır.
CallMeNorm

Yanıtlar:


163

Kodunuzla ilgili 4 sorun görüyorum:

  • Zamanlayıcı yönteminizde her zaman mevcut sayınızı 10'a ayarlıyorsunuz
  • Render yönteminde durumu güncellemeye çalışıyorsunuz
  • Durumu setStategerçekten değiştirmek için yöntem kullanmıyorsunuz
  • Aralık kimliğinizi eyalette depolamıyorsunuz

Bunu düzeltmeye çalışalım:

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>
    );
}

Bu, 10'dan -N'ye düşen bir zamanlayıcıyla sonuçlanır. 0'a düşen zamanlayıcı istiyorsanız, biraz değiştirilmiş versiyonu kullanabilirsiniz:

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

Teşekkür ederim. Bu çok mantıklı. Hâlâ yeni başlayan biriyim ve durumun nasıl çalıştığını ve render gibi hangi "yığınların" içinde ne olduğunu anlamaya çalışıyorum.
Jose

Merak ediyorum, aralığı gerçekten ayarlamak için componentDidMount ve componentWillUnmount kullanmak gerekli midir? DÜZENLEME: En son düzenlemenizi az önce gördüm. :)
Jose

@Jose componentDidMountMüşteri tarafı olaylarını tetiklemek için doğru yer olduğunu düşünüyorum , bu yüzden geri sayımı başlatmak için kullanacağım. Başlatma için başka hangi yöntemi düşünüyorsunuz?
dotnetom

4
SetInterval değerini durumun bir parçası olarak saklamaya gerçekten gerek yok çünkü bu, oluşturmayı etkilemiyor
Gil

1
ES6'da, buna erişmek için sınıfı bağlamayı unutmayın: this.timer.bind(this)vetimer() { ... }
Vincent Decaux

32

Kullanılarak 10 saniyelik geri sayım güncellendi 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;

20

Kullanarak 10 saniyelik geri sayım Güncelleme Hooks (eğer devlet kullanmak ve diğer bir sınıf yazmadan özelliklerini tepki sağlayan yeni bir özellik önerisi. Bunlar şu anda konum v16.7.0-alfa Tepki).

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'));

React 16.8 ile, React Kancaları kararlı sürümde mevcuttur.
Greg Herbowicz

Not: Dikkat edin! Bu doğru kod değil!
likern

4

SetInterval uygulamak için bir React Hook yaklaşımı arayan biri varsa. Dan Abramov blogunda bundan bahsetti . Sınıf yaklaşımı da dahil olmak üzere konu hakkında iyi bir okuma istiyorsanız, kontrol edin. Temel olarak kod, setInterval'i bildirimsel olarak döndüren özel bir Hook'tur.

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

Ayrıca kolaylık sağlamak için CodeSandbox bağlantısını yayınlayın: https://codesandbox.io/s/105x531vkq


2

Teşekkürler @dotnetom, @ greg-herbowicz

"This.state is undefined" döndürürse - bağlama zamanlayıcı işlevi:

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

0

React sınıfında her saniye durum güncelleniyor. My index.js'nin geçerli zamanı döndüren bir işlevi geçtiğini unutmayın.

import React from "react";

class App extends React.Component {
  constructor(props){
    super(props)

    this.state = {
      time: this.props.time,

    }        
  }
  updateMe() {
    setInterval(()=>{this.setState({time:this.state.time})},1000)        
  }
  render(){
  return (
    <div className="container">
      <h1>{this.state.time()}</h1>
      <button onClick={() => this.updateMe()}>Get Time</button>
    </div>
  );
}
}
export default App;

0

SetInterval'ı React Hooks ile yönetin:

  const [seconds, setSeconds] = useState(0)

  const interval = useRef(null)

  useEffect(() => { if (seconds === 60) stopCounter() }, [seconds])

  const startCounter = () => interval.current = setInterval(() => {
    setSeconds(prevState => prevState + 1)
  }, 1000)

  const stopCounter = () => clearInterval(interval.current)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.