Mengapa memanggil reaksi metode setState tidak mengubah status segera?


326

Saya membaca bagian Formulirdokumentasi dan baru saja mencoba kode ini untuk menunjukkan onChangepenggunaan ( JSBIN ).

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

Ketika saya memperbarui <input/>nilai di browser, yang kedua console.logdi dalam handleChangecallback mencetak sama valuedengan yang pertama console.log, Mengapa saya tidak bisa melihat hasil this.setState({value: event.target.value})dalam lingkup handleChangecallback?


Jawaban:


615

Dari dokumentasi Bereaksi :

setState()tidak segera bermutasi this.statetetapi menciptakan transisi status tertunda. Mengakses this.statesetelah memanggil metode ini berpotensi mengembalikan nilai yang ada. Tidak ada jaminan operasi sinkron dari panggilan ke setStatedan panggilan dapat dikumpulkan untuk keuntungan kinerja.

Jika Anda ingin fungsi dijalankan setelah perubahan status terjadi, berikan sebagai panggilan balik.

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});

Jawaban yang bagus. Pengamatan yang perlu saya lakukan adalah berhati-hati menggunakan valueLink. Ini berfungsi baik jika Anda tidak perlu memformat / menutupi input.
Dherik

42
Anda mungkin juga ingin check out componentDidUpdate. Ini akan dipanggil setelah negara berubah.
Keysox

1
Pertanyaan cepat jika saya bisa, saya melihat begitu kita melewati fungsi yang kita butuhkan sebagai panggilan balik ke setState, saya berharap bahwa func akan dieksekusi terlebih dahulu sebelum render () dipanggil. Tetapi saya melihat urutannya adalah setState () -> render () -> callback setState (). Apakah ini normal? Bagaimana jika kita ingin mengendalikan render kita berdasarkan pada hal-hal yang kita lakukan dalam panggilan balik? haruskahComponentUpdate ?
semuzaboi

2
Mengubah status komponen akan selalu memicu render ulang kecuali jika ada perilaku shouldComponentUpdateyang menentukan sebaliknya. Apa sebenarnya yang Anda coba lakukan dalam callback yang Anda sampaikan dan setStateingin Anda wujudkan sebelum render ulang?
Michael Parker

4
...Mengapa? Bisakah seseorang membenarkan ini?
JackHasaKeyboard

49

Seperti disebutkan dalam dokumentasi Bereaksi, tidak ada jaminan setStatedipecat secara serempak, sehingga Anda console.logdapat mengembalikan negara sebelum memperbarui.

Michael Parker menyebutkan lewat callback di dalam setState. Cara lain untuk menangani logika setelah perubahan keadaan adalah melalui componentDidUpdatemetode siklus hidup, yang merupakan metode yang direkomendasikan dalam React docs.

Secara umum kami sarankan menggunakan componentDidUpdate () untuk logika seperti itu.

Ini sangat berguna ketika mungkin ada berturut-turut setStatedipecat, dan Anda ingin memecat fungsi yang sama setelah setiap perubahan negara. Daripada menambahkan panggilan balik ke masing-masing setState, Anda dapat menempatkan fungsi di dalam componentDidUpdate, dengan logika spesifik di dalam jika perlu.

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}

16

Anda dapat mencoba menggunakan ES7 async / menunggu. Misalnya menggunakan contoh Anda:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}

Bagaimana jawaban Anda berbeda dari jawaban berkualitas tinggi lainnya?
tod

9
Jawaban lainnya adalah sehubungan dengan menggunakan panggilan balik di setState (). Saya pikir saya meletakkan ini di sini untuk mereka yang tidak menggunakan case callback. Misalnya, ketika saya menghadapi masalah ini sendiri, use case saya melibatkan switch case pada status yang diperbarui segera setelah pengaturannya. Oleh karena itu menggunakan async / menunggu lebih disukai daripada menggunakan panggilan balik.
kurokiiru

akankah ini berdampak kinerja jika saya selalu menggunakan menunggu selalu ketika saya ingin memperbarui beberapa negara dan kemudian menunggu itu telah diperbarui? Dan jika saya meletakkan beberapa setState menunggu dalam satu rantai di bawah yang lain, akankah ia membuat setelah setiap pembaruan setState? atau setelah pembaruan setState terakhir?
user2774480


Pada apa yang Anda minta pada user2774480, saya yakin semuanya tergantung pada use case khusus untuk menentukan implementasi mana yang akan digunakan. Jika beberapa setState digunakan dalam sebuah rantai, kinerja akan terpengaruh, dan ya, itu akan merender setelah setiap setState, tetapi koreksi saya jika saya salah.
kurokiiru


-1

async-await sintaks berfungsi sempurna untuk sesuatu seperti berikut ...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

-1

Sederhananya - this.setState ({data: value}) bersifat asinkron yang berarti ia keluar dari Call Stack dan hanya kembali ke Call Stack kecuali jika diselesaikan.

Harap baca tentang Perulangan Acara untuk memiliki gambaran yang jelas tentang sifat Asinkron di JS dan mengapa diperlukan waktu untuk memperbarui -

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

Karenanya -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

karena butuh waktu untuk memperbarui. Untuk mencapai proses di atas -

    this.setState({data:value},function () {
     console.log(this.state.data);
    });
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.