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?

tarrsalah
sumber
Jika Anda menggunakan kait, lihat metode set useState yang tidak langsung mencerminkan perubahan .
Emile Bergeron

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);
});
Michael Parker
sumber
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();  
  }
}
Yo Wakita
sumber
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);
}
kurokiiru
sumber
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}`);
}
Ritwik
sumber
-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);
    });
Vishal Bisht
sumber