ReactJS: setTimeout () không hoạt động?


100

Có mã này trong tâm trí:

var Component = React.createClass({

    getInitialState: function () {
        return {position: 0};    
    },

    componentDidMount: function () {
        setTimeout(this.setState({position: 1}), 3000);
    },

    render: function () {
         return (
            <div className="component">
                {this.state.position}
            </div>
         ); 
    }

});

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);

Không phải trạng thái sẽ thay đổi chỉ sau 3 giây sao? Nó thay đổi ngay lập tức.

Mục tiêu chính của tôi ở đây là thay đổi trạng thái 3 giây một lần (với setInterval()), nhưng vì nó không hoạt động nên tôi đã thử setTimeout(), điều này cũng không hoạt động. Có đèn nào trên này không? Cảm ơn!


2
Nếu bạn có foo(bar())thì barđược thực thi đầu tiên và giá trị trả về của nó được chuyển đến foo.
Felix Kling

@FelixKling điều đó có vẻ đúng, nhưng không phù hợp. Vì foo()ở đây chính xác là thực thi barsau thời gian chờ mong muốn. Hay tôi hoàn toàn sai và nó thực thi ngay lập tức, và chỉ trả lại giá trị sau thời gian mong muốn?
jbarradas

3
"Vì foo () ở đây chính xác là thanh thực thi sau thời gian chờ mong muốn." Đúng, đó là lý do tại sao bạn phải vượt qua bar, không gọi nó và chuyển giá trị trả về của nó. Bạn có mong đợi hành vi của foo(bar())thay đổi, tùy thuộc vào những gì foođang làm không? Điều đó sẽ thực sự kỳ lạ.
Felix Kling

Câu trả lời:


241

Làm

setTimeout(
    function() {
        this.setState({ position: 1 });
    }
    .bind(this),
    3000
);

Nếu không, bạn đang chuyển kết quả của setStatetới setTimeout.

Bạn cũng có thể sử dụng các hàm mũi tên của ES6 để tránh sử dụng thistừ khóa:

setTimeout(
  () => this.setState({ position: 1 }), 
  3000
);

1
Yeah có ý nghĩa và nó đang hoạt động. Nhưng không phải hàm () là một hàm? Vậy tại sao chúng ta cần phải ràng buộc nó? Tôi đã thử và nó thực sự cần thiết, tôi chỉ muốn biết tại sao. Đánh giá cao sự giúp đỡ của bạn :)
jbarradas

Tôi không hiểu tại sao bạn lại nói rằng nó sẽ chuyển kết quả đến setTimeout, làm thế nào mà điều này không hoạt động? Hành vi trong trường hợp đó là gì?
Tích

16
dành cho những người bạn thích sử dụng các hàm mũi tên của ES6: setTimeout(() => {this.setState({ position: 1 })}, 3000)@PositiveGuy không chắc bạn đã tự nghiên cứu vấn đề này từ khi câu hỏi này được đăng hay chưa, nhưng trong trường hợp bạn chưa: Ví dụ ban đầu của Daniel cần .bind(this)giới hạn thisngữ cảnh setState- nếu không , thissẽ tự động tham chiếu đến ngữ cảnh mà nó được gọi (trong trường hợp này, ẩn danh functionđược chuyển đến setTimeout). Tuy nhiên, các hàm mũi tên của ES6 có phạm vi từ vựng - chúng giới hạn thistrong ngữ cảnh mà chúng được gọi.
Zac Collier

1
Không hoạt động ... setTimeout (() => {if (! This.props.logoIsLoading &&! This.props.isLoading) {console.log ('Chúng ta sẽ xảy ra chứ?'); This.setState ({.. .this.state, shouldUpdate: false, itemToUpdate: null, modalIsOpen: false, modalTitle: 'Thêm tổ chức mới'});}}, 100); Nó trong ngữ cảnh của lớp đường cú pháp lớp Tổ chức mở rộng Thành phần {console.log không bao giờ nhận được console.log ('Chúng ta sẽ xảy ra chứ?'); Mọi thứ trước và sau khi nó được ghi lại.
juslintek

@juslintek xác định không hoạt động. vui lòng hỏi một câu hỏi mới nếu cần.
Daniel A. White

150
setTimeout(() => {
  this.setState({ position: 1 });
}, 3000);

Ở trên cũng sẽ hoạt động vì hàm mũi tên của ES6 không thay đổi ngữ cảnh của this.


3
Cú pháp ES6 phải là câu trả lời được chấp nhận cho các phương pháp hay nhất trong React. Cả hai đều sẽ hoạt động, nhưng điều này là thanh lịch hơn và xử lý this.
mccambridge

24

Bất cứ khi nào chúng tôi tạo thời gian chờ, chúng tôi nên xóa nó trên componentWillUnmount, nếu nó chưa kích hoạt.

      let myVar;
         const Component = React.createClass({

            getInitialState: function () {
                return {position: 0};    
            },

            componentDidMount: function () {
                 myVar = setTimeout(()=> this.setState({position: 1}), 3000)
            },

            componentWillUnmount: () => {
              clearTimeout(myVar);
             };
            render: function () {
                 return (
                    <div className="component">
                        {this.state.position}
                    </div>
                 ); 
            }

        });

ReactDOM.render(
    <Component />,
    document.getElementById('main')
);

11

Tôi biết điều này hơi cũ, nhưng điều quan trọng cần lưu ý là React đề xuất xóa khoảng thời gian khi thành phần ngắt kết nối: https://reactjs.org/docs/state-and-lifecycle.html

Vì vậy, tôi muốn thêm câu trả lời này vào cuộc thảo luận này:

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

8

setStateđang được gọi ngay lập tức do dấu ngoặc đơn! Gói nó trong một hàm ẩn danh, sau đó gọi nó:

setTimeout(function() {
    this.setState({position: 1})
}.bind(this), 3000);

6

Bạn đã không nói ai đã gọi setTimeout

Đây là cách bạn gọi thời gian chờ mà không cần gọi các chức năng bổ sung.

1. Bạn có thể làm điều này mà không cần thực hiện các chức năng bổ sung.

setTimeout(this.setState.bind(this, {position:1}), 3000);

Sử dụng function.prototype.bind ()

setTimeout lấy vị trí của hàm và giữ nó trong ngữ cảnh.

2. Một cách khác để làm điều tương tự ngay cả bằng cách viết ít mã hơn.

setTimeout(this.setState, 3000, {position:1});

Có thể sử dụng cùng một phương thức ràng buộc tại một số điểm

SetTimeout chỉ lấy vị trí của hàm và hàm đã có ngữ cảnh? Dù sao, nó hoạt động!

LƯU Ý: Chúng hoạt động với bất kỳ chức năng nào bạn sử dụng trong js.


5

Phạm vi mã của bạn ( this) sẽ là windowđối tượng của bạn , không phải thành phần phản ứng của bạn và đó là lý dosetTimeout(this.setState({position: 1}), 3000) sẽ sụp đổ theo cách này.

Điều đó đến từ javascript không phải React, nó là js đóng


Vì vậy, để liên kết phạm vi thành phần phản ứng hiện tại của bạn, hãy làm như sau:

setTimeout(function(){this.setState({position: 1})}.bind(this), 3000);

Hoặc nếu trình duyệt của bạn hỗ trợ es6 hoặc projs của bạn có hỗ trợ biên dịch es6 thành es5, hãy thử chức năng arrow, vì arrow func là để khắc phục sự cố 'này':

setTimeout(()=>this.setState({position: 1}), 3000);

3

Có 3 cách để truy cập phạm vi bên trong của hàm 'setTimeout'

Đầu tiên,

const self = this
setTimeout(function() {
  self.setState({position:1})
}, 3000)

Thứ hai là sử dụng hàm mũi tên của ES6, vì hàm mũi tên không có phạm vi chính nó (cái này)

setTimeout(()=> {
   this.setState({position:1})
}, 3000)

Thứ ba là ràng buộc phạm vi bên trong của hàm

setTimeout(function(){
   this.setState({position:1})
}.bind(this), 3000)

1

Bạn đã khai báo lỗi cú pháp, hãy sử dụng khai báo setTimeout thích hợp

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}
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.