Bereaksi setState tidak memperbarui status


91

Jadi saya punya ini:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({dealersOverallTotal: total});
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealersDeckTotal hanyalah sebuah larik angka, [1, 5, 9]misalnya this.state.dealersOverallTotal, tidak memberikan total yang benar, tetapi totalapakah? Saya bahkan melakukan penundaan waktu tunggu untuk melihat apakah ini menyelesaikan masalah. ada yang jelas atau haruskah saya memposting lebih banyak kode?



@Assan bersulang !!
The worm

Selain apa yang dikatakan dalam jawaban, Anda secara eksplisit mencatat nilai status, sebelum Anda menelepon setState.
Felix Kling

1
@FelixKling tidak, saya menelepon this.state setelah saya menyetelnya. Saya mencatat variabel sebelumnya. tidak?
The worm

Karena batas waktu Anda setStatememang dieksekusi setelah Anda masuk status. Saya pikir apa yang ingin Anda lakukan dalam debugging adalah meletakkan console.logbagian di dalam batas waktu, dan di setStateluar.
Fabian Schultz

Jawaban:


182

setState()biasanya asinkron, yang artinya pada saat Anda console.logmenyatakan statusnya, belum diperbarui. Coba masukkan log ke dalam callback setState()metode tersebut. Ini dijalankan setelah perubahan status selesai:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

1
Selain itu, OP secara eksplisit mencatat nilai negara sebelum mereka memanggil setState.
Felix Kling

Ini berfungsi untuk saya juga, di masa lalu saya telah menggunakan ini: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'tetapi untuk beberapa alasan itu tidak memburuk lagi, ketika saya memperbarui kode seperti yang dijelaskan di atas itu berfungsi. ada tahu mengapa?
Jozcar

@Jozcar Harus berfungsi juga, sintaks tidak benar (tanda kurung hilang):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTl Tolong beritahu saya apa yang harus saya lakukan untuk mengatasi masalah ini.
Johncy

Ini tidak bekerja jika Anda menggunakan useStatehook dalam komponen fungsional. Gunakan useEffectsebagai gantinya untuk efek setelah rendering.
Hasan Sefa Ozalp

16

setState tidak sinkron. Anda dapat menggunakan metode callback untuk mendapatkan status diperbarui.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }

10

Menggunakan async / await

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

Saya melakukan hal yang sama Bekerja untuk saya
prodeveloper

8

The setState()operasi asynchronous dan karenanya Anda console.log()akan dieksekusi sebelum setState()bermutasi nilai-nilai dan karenanya Anda melihat hasilnya.

Untuk mengatasinya, masukkan nilai dalam fungsi callback setState(), seperti:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript selalu sinkron.
Santosh Singh

1
@santoshsingh Anda memiliki kesalahpahaman. Panggilan API, waktu tunggu semua terjadi secara asinkron.
Shubham Khatri

Seperti yang Anda sebutkan di atas bahwa javascript itu tidak sinkron --- itu tidak benar. Ini terutama sinkron dan untuk kasus itu asinkron. stackoverflow.com/questions/2035645/…
Santosh Singh

@tokopedia. Ohh, itu adalah kesalahan saya. Tidak membentuk kalimat dengan benar
Shubham Khatri

penggunaan callback yang sangat cerdik untuk memastikan status diperbarui sebelum panggilan berikutnya!
pengguna1204214

5

Untuk pengait, Anda harus menggunakan useEffectpengait.

const [fruit, setFruit] = useState('');

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

Bagus, ini berfungsi dengan useEffect. Tapi mengapa itu membutuhkannya?
alex351

useEffectberjalan pada setiap render ulang, dan jika item yang diteruskan ke dalam larik adalah pasir variabel status berubah. Jadi ketika buah berubah dan komponen dirender ulang, useEffect itu akan berjalan.
Siraj Alam

Saya menjalankan buah setFruit dan console.log di luar useEffect, dan itu tidak berubah. : /
alex351

3

Setstate adalah asynchronous dalam bereaksi, jadi untuk melihat status yang diperbarui di konsol gunakan callback seperti yang ditunjukkan di bawah ini (Fungsi callback akan dijalankan setelah update setstate)

masukkan deskripsi gambar di sini

Metode di bawah ini "tidak disarankan" tetapi untuk pemahaman, jika Anda mengubah status secara langsung, Anda dapat melihat status yang diperbarui di baris berikutnya. Saya ulangi ini "tidak disarankan"

masukkan deskripsi gambar di sini


TERIMA KASIH ini dia, Anda harus langsung mengatur variabel
notacorn


0

Saya mengalami masalah saat menyetel status reaksi beberapa kali (selalu menggunakan status default). Mengikuti masalah react / github ini berhasil untuk saya

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});

0

Saya memiliki situasi yang sama dengan beberapa kode yang berbelit-belit, dan tidak ada dari saran yang ada yang berhasil untuk saya.

Masalah saya adalah yang setStateterjadi dari fungsi panggilan balik, yang dikeluarkan oleh salah satu komponen. Dan kecurigaan saya adalah bahwa panggilan itu terjadi secara sinkron, yang mencegah setStatepengaturan status sama sekali.

Sederhananya saya punya sesuatu seperti ini:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

Cara saya harus "memperbaiki" itu untuk dimasukkan doUpdate()ke dalam setTimeoutseperti ini:

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Tidak ideal, tetapi sebaliknya itu akan menjadi refactoring yang signifikan.

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.