setInterval trong ứng dụng React


101

Tôi vẫn còn khá mới trong React, nhưng tôi đã bắt đầu từ từ và tôi đã gặp phải điều gì đó mà tôi đang mắc kẹt.

Tôi đang cố gắng xây dựng một thành phần "bộ đếm thời gian" trong React và thành thật mà nói, tôi không biết liệu mình đang làm điều này đúng (hoặc hiệu quả). Trong mã của tôi dưới đây, tôi thiết lập nhà nước để trả về một đối tượng { currentCount: 10 }và đã toying với componentDidMount, componentWillUnmountrendervà tôi chỉ có thể nhận được trạng thái để "đếm ngược" 10-9.

Câu hỏi gồm hai phần: Tôi đang làm gì sai? Và, có cách nào hiệu quả hơn để sử dụng setTimeout (thay vì sử dụng componentDidMount& componentWillUnmount) không?

Cảm ơn bạn trước.

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)không còn cần thiết, phản ứng tự thực hiện điều này ngay bây giờ.
Derek Pollard,

2
Phương pháp đếm thời gian của bạn không cập nhật CURRENTCOUNT
Bryan Chen

1
@Derek bạn có chắc không? Tôi vừa bắt đầu làm việc bằng cách thêm vào this.timer.bind(this)vì this .timer riêng của nó đã không hoạt động
Sâu

6
@Theworm @Derek sai rồi, đại loại. React.createClass (không được dùng nữa) class Clock extends Componenttự động liên kết các phương thức, nhưng không tự động liên kết. Vì vậy, nó phụ thuộc vào cách bạn đang tạo các thành phần của mình liệu bạn có cần liên kết hay không.
CallMeNorm

Câu trả lời:


157

Tôi thấy 4 vấn đề với mã của bạn:

  • Trong phương pháp hẹn giờ, bạn luôn đặt số lượng hiện tại của mình thành 10
  • Bạn cố gắng cập nhật trạng thái trong phương thức kết xuất
  • Bạn không sử dụng setStatephương pháp để thực sự thay đổi trạng thái
  • Bạn không lưu trữ khoảng thời gian của mình ở trạng thái

Hãy cố gắng khắc phục điều đó:

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

Điều này sẽ dẫn đến bộ đếm thời gian giảm từ 10 xuống -N. Nếu bạn muốn bộ đếm thời gian giảm xuống 0, bạn có thể sử dụng phiên bản sửa đổi một chút:

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

Cảm ơn bạn. Điều này có rất nhiều ý nghĩa. Tôi vẫn còn là một người mới bắt đầu và tôi đang cố gắng nắm bắt cách hoạt động của trạng thái và những gì diễn ra trong các "khối", như kết xuất.
Jose

Tuy nhiên, tôi đang tự hỏi, liệu có cần sử dụng componentDidMount và componentWillUnmount để thực sự đặt khoảng thời gian không? CHỈNH SỬA: Vừa xem bản chỉnh sửa gần đây nhất của bạn. :)
Jose

@Jose Tôi nghĩ componentDidMountlà nơi thích hợp để kích hoạt các sự kiện phía máy khách, vì vậy tôi sẽ sử dụng nó để bắt đầu đếm ngược. Bạn đang nghĩ đến phương pháp nào khác để khởi tạo?
dotnetom

Tôi không có bất kỳ điều gì khác đặc biệt trong tâm trí, nhưng có vẻ thật khó hiểu khi sử dụng quá nhiều "khối" bên trong một thành phần. Tôi cho rằng đó chỉ là bản thân tôi đã quen với cách các bit và các mảnh hoạt động trong React. Một lần nữa, xin cảm ơn!
Jose

4
Thực sự không cần thiết phải lưu trữ giá trị setInterval như một phần của trạng thái vì nó không ảnh hưởng đến kết xuất
Gil

32

Đã cập nhật đếm ngược 10 giây bằng cách sử dụng 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

Đã cập nhật đếm ngược 10 giây bằng cách sử dụng Hooks (một đề xuất tính năng mới cho phép bạn sử dụng trạng thái và các tính năng khác của React mà không cần viết lớp. Chúng hiện đang ở trong 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'));

Với React 16.8, React Hooks có sẵn trong một bản phát hành ổn định.
Greg Herbowicz

2

Cảm ơn @dotnetom, @ greg-herbowicz

Nếu nó trả về "this.state là không xác định" - hàm hẹn giờ ràng buộc:

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

2

Nếu bất kỳ ai đang tìm kiếm một cách tiếp cận React Hook để triển khai setInterval. Dan Abramov đã nói về nó trên blog của mình . Hãy xem nó nếu bạn muốn đọc tốt về chủ đề bao gồm cả cách tiếp cận Lớp học. Về cơ bản, mã là một Hook tùy chỉnh biến setInterval như một phần khai báo.

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

Cũng đăng liên kết CodeSandbox để tiện theo dõi: https://codesandbox.io/s/105x531vkq


0

Cập nhật trạng thái mỗi giây trong lớp phản ứng. Lưu ý rằng index.js của tôi chuyển một hàm trả về thời gian hiện tại.

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.