setState tidak segera memperbarui status

110

Saya ingin bertanya mengapa status saya tidak berubah ketika saya melakukan acara onclick. Saya telah mencari beberapa waktu yang lalu bahwa saya perlu mengikat fungsi onclick di konstruktor tetapi masih negara tidak memperbarui. Ini kode saya:

import React from 'react';

import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';

import BoardAddModal from 'components/board/BoardAddModal.jsx';

import style from 'styles/boarditem.css';

class BoardAdd extends React.Component {

    constructor(props){
        super(props);

        this.state = {
            boardAddModalShow: false
        }

        this.openAddBoardModal = this.openAddBoardModal.bind(this);
    }
    openAddBoardModal(){
        this.setState({ boardAddModalShow: true });
// After setting a new state it still return a false value
        console.log(this.state.boardAddModalShow);

    }

    render() {

        return (
            <Col lg={3}>
                <a href="javascript:;" className={style.boardItemAdd} onClick={this.openAddBoardModal}>
                    <div className={[style.boardItemContainer,style.boardItemGray].join(' ')}>
                        Create New Board
                    </div>
                </a>



            </Col>
        )
    }
}

export default BoardAdd
Sydney Loteria
sumber
5
Jawaban yang Anda terima untuk pertanyaan ini tidak masuk akal. setStatetidak membalas janji. Jika berhasil, itu hanya berfungsi karena awaitmemperkenalkan satu "centang" asinkron ke dalam fungsi, dan kebetulan pembaruan status diproses selama centang itu. Itu tidak dijamin. Seperti yang dikatakan jawaban ini , Anda perlu menggunakan callback penyelesaian (jika Anda benar-benar perlu melakukan sesuatu setelah status diperbarui, yang tidak biasa; biasanya, Anda hanya ingin merender ulang, yang terjadi secara otomatis).
TJ Crowder
Akan lebih baik jika Anda tidak menerima jawaban yang diterima saat ini atau menerima jawaban yang benar, karena ini kemudian dapat digunakan sebagai duplikat untuk banyak pertanyaan lainnya. Memiliki jawaban yang salah di bagian atas menyesatkan.
Guy Incognito

Jawaban:

13

Panggilan balik ini benar-benar berantakan. Cukup gunakan async await sebagai gantinya:

async openAddBoardModal(){
    await this.setState({ boardAddModalShow: true });
    console.log(this.state.boardAddModalShow);
}
Spock
sumber
29
Itu tidak masuk akal. React's setStatetidak mengembalikan janji.
TJ Crowder
17
@TJCder benar. setStatetidak mengembalikan janji, jadi TIDAK harus ditunggu. Yang mengatakan, saya pikir saya bisa melihat mengapa ini berfungsi untuk beberapa orang, karena await menempatkan cara kerja setState di dalam tumpukan panggilan di depan sisa fungsi, sehingga diproses terlebih dahulu, dan dengan demikian tampak seperti keadaan telah set. Jika setState memiliki atau mengimplementasikan panggilan asynchronous baru, jawaban ini akan gagal.Untuk mengimplementasikan fungsi ini dengan benar, Anda dapat menggunakan ini:await new Promise(resolve => this.setState({ boardAddModalShow: true }, () => resolve()))
Mike Richards
Bagaimana cara async this.setState({})memecahkan masalah saya? Kami memiliki kode yang berfungsi, beberapa pengembangan lagi telah dilakukan tetapi tidak ada yang mengubah bagian aplikasi itu. Hanya satu dari dua objek di setState yang diperbarui, menjadikannya asinkron mengembalikan fungsionalitas kembali dan sekarang kedua objek diperbarui dengan benar. Aku benar-benar tidak tahu apa yang salah.
Ondřej Ševčík
Saya menemukan pertanyaan ini, tetapi solusi ini tidak berhasil untuk saya, saya belum menyelesaikan masalah saya tetapi saya menemukan bacaan yang bagus di sini: ozmoroz.com/2018/11/why-my-setstate-doesnt-work
carmolim
151

Status Anda memerlukan waktu untuk bermutasi, dan karena console.log(this.state.boardAddModalShow)dijalankan sebelum status bermutasi, Anda mendapatkan nilai sebelumnya sebagai keluaran. Jadi, Anda perlu menulis konsol di callback ke setStatefungsi tersebut

openAddBoardModal() {
  this.setState({ boardAddModalShow: true }, function () {
    console.log(this.state.boardAddModalShow);
  });
}

setStateasinkron. Ini berarti Anda tidak dapat menyebutnya dalam satu baris dan menganggap keadaan telah berubah di baris berikutnya.

Menurut dokumen React

setState()tidak langsung bermutasi this.statetetapi menciptakan transisi status tertunda. Mengakses this.statesetelah memanggil metode ini berpotensi mengembalikan nilai yang sudah ada. Tidak ada jaminan operasi sinkron dari panggilan ke setState dan panggilan dapat dikelompokkan untuk mendapatkan performa.

Mengapa mereka membuat setStateasinkron

Ini karena setStatemengubah status dan menyebabkan perenderan ulang. Ini bisa menjadi operasi yang mahal dan membuatnya sinkron mungkin membuat browser tidak responsif.

Dengan demikian, setStatepanggilan bersifat asinkron serta dikumpulkan untuk pengalaman dan kinerja UI yang lebih baik.

Shubham Khatri
sumber
Sampai sekarang ini adalah ide yang bagus, TAPI bagaimana jika kita tidak dapat menggunakan console.log karena Anda menggunakan aturan eslint?
maudev
2
@maudev, aturan eslint menghentikan Anda untuk memiliki console.logs sehingga mereka tidak berakhir dalam produksi, tetapi contoh di atas murni untuk debugging. dan console.log dan diganti dengan tindakan yang memperhitungkan status yang diperbarui
Shubham Khatri
1
Bagaimana jika panggilan balik tidak berfungsi seperti yang Anda katakan? milikku tidak!
Alex Jolig
@ShubhamKhatri ini bekerja dengan baik untuk saya, namun saya kemudian mencoba untuk meneruskan nilai status sebagai prop ke dalam komponen anak, dan ketika saya console.logprop, saya mendapatkan nilai yang sama dengan keadaan aslinya.
Archie Margretts
36

Untungnya setState() menerima panggilan balik. Dan di sinilah kita mendapatkan status diperbarui.

Pertimbangkan contoh ini.

this.setState({ name: "myname" }, () => {                              
        //callback
        console.log(this.state.name) // myname
      });

Jadi Saat callback diaktifkan, this.state adalah status yang diperbarui.
Anda bisa mendapatkan mutated/updateddata di callback.

Mustkeem K
sumber
1
Anda juga dapat menggunakan callback ini untuk meneruskan fungsi apa pun initMap(), misalnya
Dende
Jalan untuk pergi! Akhirnya masalah saya terpecahkan. Terima kasih banyak.
Ahmet Halilović
12

Karena setSatate adalah fungsi asinkron, jadi Anda perlu mengkonsol status sebagai callback seperti ini.

openAddBoardModal(){
    this.setState({ boardAddModalShow: true }, () => {
        console.log(this.state.boardAddModalShow)
    });
}
Adnan shah
sumber
7

setState()tidak selalu segera memperbarui komponen. Itu mungkin batch atau menunda pembaruan sampai nanti. Ini membuat membaca this.state tepat setelah memanggil setState()potensi jebakan. Sebagai gantinya, gunakan componentDidUpdateatau setStatecallback ( setState(updater, callback)), yang salah satunya dijamin akan diaktifkan setelah pembaruan diterapkan. Jika Anda perlu menyetel keadaan berdasarkan keadaan sebelumnya, baca tentang argumen pembaru di bawah.

setState()akan selalu mengarah ke render ulang kecuali shouldComponentUpdate()mengembalikan false. Jika objek yang bisa berubah sedang digunakan dan logika rendering bersyarat tidak dapat diimplementasikan shouldComponentUpdate(), memanggil setState()hanya ketika keadaan baru berbeda dari keadaan sebelumnya akan menghindari perenderan ulang yang tidak perlu.

Argumen pertama adalah fungsi pembaru dengan tanda tangan:

(state, props) => stateChange

stateadalah referensi ke status komponen pada saat perubahan diterapkan. Ini tidak boleh langsung bermutasi. Sebaliknya, perubahan harus direpresentasikan dengan membangun objek baru berdasarkan masukan dari status dan alat peraga. Misalnya, kita ingin menambah nilai dalam status dengan props.step:

this.setState((state, props) => {
    return {counter: state.counter + props.step};
});
Aman Seth
sumber
2

Jika Anda ingin melacak keadaan sedang diperbarui atau tidak maka cara lain untuk melakukan hal yang sama adalah

_stateUpdated(){
  console.log(this.state. boardAddModalShow);
}

openAddBoardModal(){
  this.setState(
    {boardAddModalShow: true}, 
    this._stateUpdated.bind(this)
  );
}

Dengan cara ini Anda dapat memanggil metode "_stateUpdated" setiap kali Anda mencoba memperbarui status untuk debugging.

Ravin Gupta
sumber
1

setState()asinkron. Cara terbaik untuk memverifikasi apakah negara sedang memperbarui akan di componentDidUpdate()dan tidak meletakkan console.log(this.state.boardAddModalShow)setelah this.setState({ boardAddModalShow: true }).

menurut React Docs

Pikirkan setState () sebagai permintaan daripada perintah langsung untuk memperbarui komponen. Untuk performa yang lebih baik, React mungkin menundanya, dan kemudian mengupdate beberapa komponen dalam sekali jalan. React tidak menjamin bahwa perubahan status diterapkan dengan segera

stuli
sumber
1

Menurut React Docs

React tidak menjamin bahwa perubahan status diterapkan dengan segera. Hal ini membuat pembacaan this.state tepat setelah memanggil setState () menjadi potensial pitfalldan berpotensi mengembalikan existingnilai karena asyncsifatnya. Sebagai gantinya, gunakan componentDidUpdateatau setStatecallback yang dijalankan tepat setelah operasi setState berhasil. Secara umum, kami merekomendasikan penggunaan componentDidUpdate()untuk logika seperti itu.

Contoh:

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      counter: 1
    };
  }
  componentDidUpdate() {
    console.log("componentDidUpdate fired");
    console.log("STATE", this.state);
  }

  updateState = () => {
    this.setState(
      (state, props) => {
        return { counter: state.counter + 1 };
      });
  };
  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <button onClick={this.updateState}>Update State</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

khizer
sumber
1

Bagi siapa pun yang mencoba melakukan ini dengan pengait, Anda perlu useEffect.

function App() {
  const [x, setX] = useState(5)
  const [y, setY] = useState(15) 

  console.log("Element is rendered:", x, y)

  // setting y does not trigger the effect
  // the second argument is an array of dependencies
  useEffect(() => console.log("re-render because x changed:", x), [x])

  function handleXClick() {
    console.log("x before setting:", x)
    setX(10)
    console.log("x in *line* after setting:", x)
  }

  return <>
    <div> x is {x}. </div>
    <button onClick={handleXClick}> set x to 10</button>
    <div> y is {y}. </div>
    <button onClick={() => setY(20)}> set y to 20</button>
  </>
}

Keluaran:

Element is rendered: 5 15
re-render because x changed: 5
(press x button)
x before setting: 5
x in *line* after setting: 5
Element is rendered: 10 15
re-render because x changed: 10
(press y button)
Element is rendered: 10 20
Luke Miles
sumber
-1

ketika saya menjalankan kode dan memeriksa output saya di konsol itu menunjukkan bahwa itu tidak ditentukan. Setelah saya mencari-cari dan menemukan sesuatu yang berhasil untuk saya.

componentDidUpdate(){}

Saya menambahkan metode ini dalam kode saya setelah konstruktor (). periksa siklus hidup alur kerja react native.

https://images.app.goo.gl/BVRAi4ea2P4LchqJ8

Pravin Ghorle
sumber
-2
 this.setState({
    isMonthFee: !this.state.isMonthFee,
  }, () => {
    console.log(this.state.isMonthFee);
  })
Atchutha rama reddy Karri
sumber
2
Ini persis seperti yang dijelaskan oleh jawaban yang paling banyak dipilih, tetapi tanpa penjelasan apa pun dan terlambat 3 tahun. Harap jangan memposting jawaban duplikat kecuali Anda memiliki sesuatu yang relevan untuk ditambahkan.
Emile Bergeron
-2

Ya karena setState adalah fungsi asynchronous. Cara terbaik untuk menyetel status tepat setelah Anda menulis set state adalah dengan menggunakan Object.assign seperti ini: Misalnya Anda ingin menyetel properti isValid menjadi true, lakukan seperti ini


Object.assign (this.state, {isValid: true})


Anda dapat mengakses status yang diperbarui segera setelah menulis baris ini.

Dipanshu Sharma
sumber
Jangan lakukan ini, ini akan mengubah status saat ini, yang merupakan anti-pola.
Emile Bergeron