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?

Cacing
sumber
@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');
}); 
Fabian Schultz
sumber
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));
 }
Mahesh Joshi
sumber
10

Menggunakan async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}
Dev01
sumber
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)
Shubham Khatri
sumber
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])
Siraj Alam
sumber
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

mokesh moha
sumber
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
  };
});
Arun Gopalpuri
sumber
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.

zmekanik
sumber