ReactJS: setTimeout () tidak berfungsi?

102

Memperhatikan kode ini:

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

Bukankah keadaan seharusnya berubah hanya setelah 3 detik? Ini segera berubah.

Tujuan utama saya di sini adalah mengubah status setiap 3 detik (dengan setInterval()), tetapi karena tidak berhasil, saya mencoba setTimeout(), yang juga tidak berfungsi. Ada lampu di sini? Terima kasih!

jbarradas.dll
sumber
2
Jika Anda memiliki foo(bar())maka baryang dieksekusi pertama dan nilai kembali diteruskan ke foo.
Felix Kling
@FelixKling yang sepertinya benar, tetapi tidak sesuai. Karena di foo()sini persis untuk mengeksekusi barsetelah waktu tunggu yang diinginkan. Atau apakah saya benar-benar salah dan langsung dijalankan, dan hanya mengembalikan nilai setelah waktu yang diinginkan?
jbarradas
3
"Karena foo () di sini persis untuk mengeksekusi bar setelah waktu tunggu yang diinginkan." Benar, itulah mengapa Anda harus lulus bar, bukan menyebutnya dan meneruskan nilai kembaliannya. Apakah Anda mengharapkan perilaku foo(bar())berubah, tergantung apa fooyang dilakukannya? Itu akan sangat aneh.
Felix Kling

Jawaban:

245

Melakukan

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

Jika tidak, Anda meneruskan hasil dari setStateke setTimeout.

Anda juga dapat menggunakan fungsi panah ES6 untuk menghindari penggunaan thiskata kunci:

setTimeout(
  () => this.setState({ position: 1 }), 
  3000
);
Daniel A. White
sumber
1
Ya masuk akal dan berhasil. Tapi bukankah function () sebuah fungsi? Jadi mengapa kita perlu mengikatnya? Saya sudah mencoba dan itu benar-benar dibutuhkan, saya hanya ingin tahu mengapa. Menghargai bantuan Anda :)
jbarradas
Saya tidak mengerti mengapa Anda mengatakan itu akan meneruskan hasilnya ke setTimeout, bagaimana itu tidak membuat ini berfungsi? Apa perilaku dalam kasus itu?
PositiveGuy
16
bagi Anda yang lebih suka menggunakan fungsi panah ES6: setTimeout(() => {this.setState({ position: 1 })}, 3000)@PositiveGuy tidak yakin apakah Anda telah meneliti ini sendiri sejak pertanyaan ini diposting, tetapi jika Anda belum: Contoh asli Daniel perlu .bind(this)membatasi thiskonteks ke setState- jika tidak , thisakan secara otomatis merujuk ke konteks di mana ia dipanggil (dalam hal ini, anonim functionsedang diteruskan setTimeout). Fungsi panah ES6, bagaimanapun, dibatasi secara leksikal - mereka membatasi thispada konteks di mana mereka dipanggil.
Zac Collier
1
Tidak berfungsi ... setTimeout (() => {if (! This.props.logoIsLoading &&! This.props.isLoading) {console.log ('Apakah kita akan terjadi?'); This.setState ({.. .this.state, shouldUpdate: false, itemToUpdate: null, modalIsOpen: false, modalTitle: 'Tambahkan Organisasi Baru'});}}, 100); Ini dalam konteks kelas gula sintaks kelas Organisasi memperluas Komponen {console.log tidak pernah mendapat console.log ('Akankah kita terjadi?'); Segala sesuatu sebelum dan sesudah itu dicatat.
juslintek
@juslintek define tidak berfungsi. tolong ajukan pertanyaan baru jika perlu.
Daniel A. White
150
setTimeout(() => {
  this.setState({ position: 1 });
}, 3000);

Di atas juga akan berfungsi karena fungsi panah ES6 tidak mengubah konteks this.

Steven Scaffidi
sumber
3
Sintaks ES6 harus menjadi jawaban yang diterima untuk praktik terbaik di React. Keduanya akan bekerja, tetapi ini lebih elegan dan gagang this.
mccambridge
24

Setiap kali kita membuat waktu tunggu, kita harus menghapusnya di componentWillUnmount, jika belum diaktifkan.

      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')
);
Khalid Azam
sumber
11

Saya tahu ini agak lama, tetapi penting untuk diperhatikan bahwa React merekomendasikan untuk menghapus interval ketika komponen dilepas: https://reactjs.org/docs/state-and-lifecycle.html

Jadi saya ingin menambahkan jawaban ini ke diskusi ini:

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

setStatesedang dipanggil segera karena tanda kurung! Bungkus dalam fungsi anonim, lalu panggil:

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

Anda tidak memberi tahu siapa yang menelepon setTimeout

Di sini cara Anda memanggil waktu tunggu tanpa memanggil fungsi tambahan.

1. Anda dapat melakukan ini tanpa membuat fungsi tambahan.

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

Menggunakan function.prototype.bind ()

setTimeout mengambil lokasi fungsi dan menyimpannya dalam konteks.

2. Cara lain untuk melakukan hal yang sama bahkan dengan menulis lebih sedikit kode.

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

Mungkin menggunakan metode mengikat yang sama di beberapa titik

SetTimeout hanya mengambil lokasi fungsi dan fungsi tersebut sudah memiliki konteks? Bagaimanapun, itu berhasil!

CATATAN: Ini bekerja dengan fungsi apa pun yang Anda gunakan di js.

Advis
sumber
5

Cakupan kode Anda ( this) akan menjadi windowobjek Anda , bukan komponen react Anda, dan itulah sebabnya setTimeout(this.setState({position: 1}), 3000)akan crash seperti ini.

Itu berasal dari javascript bukan React, itu adalah js closure


Jadi, untuk mengikat ruang lingkup komponen reaksi Anda saat ini, lakukan ini:

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

Atau jika browser Anda mendukung es6 atau projs Anda memiliki dukungan untuk mengkompilasi es6 ke es5, coba fungsi panah juga, karena fungsi panah untuk memperbaiki masalah 'ini':

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

Ada 3 cara untuk mengakses cakupan di dalam fungsi 'setTimeout'

Pertama,

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

Kedua adalah menggunakan fungsi panah ES6, karena fungsi panah tidak memiliki ruang lingkup sendiri (ini)

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

Yang ketiga adalah mengikat ruang lingkup di dalam fungsi

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

Anda melakukan kesalahan deklarasi sintaks, gunakan deklarasi setTimeout yang tepat

message:() => { 
  setTimeout(() => {this.setState({opened:false})},3000); 
  return 'Thanks for your time, have a nice day 😊! 
}
KARTHIKEYAN.A
sumber