setState, durumu hemen güncellemiyor


112

Bir onclick etkinliği yaptığımda durumumun neden değişmediğini sormak istiyorum. Bir süre önce yapıcıdaki onclick işlevini bağlamam gerektiğini araştırdım, ancak yine de durum güncellenmiyor. İşte kodum:

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

5
Bu soruya kabul ettiğiniz cevap hiçbir anlam ifade etmiyor. setStatebir söz vermez. İşe yaradı ise, bunun nedeni yalnızca çalıştı awaittanıtır bir zaman uyumsuz "kene" fonksiyonu içine ve oldu devlet güncelleştirme bu kene sırasında işlenir var olduğunu. Garantili değil. As Bu cevap diyor, sen tamamlama geri arama kullanmak gerekir (gerçekten devlet güncellendikten sonra sıradışı olan, bir şeyler yapmak gerekiyorsa; normalde, sadece otomatik hapens hangi-işlemek yeniden istiyorsunuz).
TJ Crowder

Halihazırda kabul edilen cevabı geri almanız veya doğru olanı kabul etmeniz iyi olur, çünkü bu daha sonra diğer birçok soru için kopya olarak kullanılabilir. Üstte yanlış cevap vermek yanıltıcıdır.
Guy Incognito

Yanıtlar:


12

Bu geri arama gerçekten dağınık. Bunun yerine asenkron beklemeyi kullanın:

async openAddBoardModal(){
    await this.setState({ boardAddModalShow: true });
    console.log(this.state.boardAddModalShow);
}

29
Bu hiç mantıklı değil. React setState, bir söz vermez.
TJ Crowder

17
@TJCrowder haklı. setStatebir söz vermez, bu yüzden BEKLENMEMELİDİR. Bununla birlikte, sanırım bunun neden bazı insanlar için işe yaradığını anlayabiliyorum, çünkü await, setState'in iç işleyişini işlevin geri kalanının önüne koyar, bu nedenle önce işlenir ve bu nedenle durum böyle görünüyor Ayarlamak. SetState herhangi bir yeni eşzamansız çağrı yaparsa veya uygularsa, bu cevap başarısız olur.Bu işlevi doğru şekilde uygulamak için şunu kullanabilirsiniz:await new Promise(resolve => this.setState({ boardAddModalShow: true }, () => resolve()))
Mike Richards

Sorunumu nasıl async this.setState({})çözdü? Çalışma kodumuz vardı, biraz daha geliştirme yapıldı ama uygulamanın bu kısmını hiçbir şey değiştirmedi. SetState'teki iki nesneden yalnızca biri güncellendi, bu da eşzamansız olarak işlevselliği geri döndürdü ve şimdi her iki nesne de doğru şekilde güncelleniyor. Neyin yanlış olduğu hakkında hiçbir fikrim yok.
Ondřej Ševčík

Bu soruyu buldum, ancak bu çözüm benim için işe yaramadı, sorunumu henüz çözmedim
carmolim

151

Durumunuzun değişmesi için biraz zamana ihtiyacı vardır console.log(this.state.boardAddModalShow)ve durum değişmeden önce yürütüldüğünden, önceki değeri çıktı olarak alırsınız. Bu nedenle, geri aramadaki konsolu setStateişleve yazmanız gerekir

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

setStatezaman uyumsuzdur. Bu, onu bir hatta arayamayacağınız ve bir sonrakinde durumun değiştiğini varsayamayacağınız anlamına gelir.

React belgelerine göre

setState()hemen mutasyona uğramaz, this.stateancak bekleyen bir durum geçişi oluşturur. this.stateBu yöntemi çağırdıktan sonra erişim , potansiyel olarak mevcut değeri döndürebilir. SetState'e yapılan çağrıların eşzamanlı çalışacağına dair bir garanti yoktur ve performans kazançları için çağrılar toplu olarak işlenebilir.

Neden setStateeşzamansız yaparlar

Bunun nedeni setState, durumu değiştirmesi ve yeniden oluşturmaya neden olmasıdır. Bu pahalı bir işlem olabilir ve eşzamanlı hale getirmek tarayıcıyı yanıt vermeyebilir.

Böylece, setStatearamalar eşzamansızdır ve daha iyi kullanıcı arayüzü deneyimi ve performansı için gruplandırılmıştır.


Şimdiye kadar bu harika bir fikir, AMA ya console.log'u eslint kurallarını kullandığınız için kullanamazsak?
maudev

2
@maudev, eslint kuralları, üretime girmemeleri için console.logs'a sahip olmanızı engeller, ancak yukarıdaki örnek tamamen hata ayıklama içindir. ve console.log ve güncellenmiş durumu dikkate alan bir eylemle değiştirilecektir
Shubham Khatri

1
Ya geri arama söylediğiniz gibi çalışmazsa? benimki değil!
Alex Jolig

@ShubhamKhatri bu benim için harika çalıştı, ancak daha sonra bir pervane olarak durum değerini bir alt bileşene aktarmaya çalıştım console.logve pervane olduğumda, orijinal durumla aynı değeri alıyorum.
Archie Margretts

36

Neyse ki setState() bir geri arama alıyor. Ve bu güncel durumu aldığımız yer.

Bu örneği düşünün.

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

Yani geri arama tetiklendiğinde, this.state güncellenmiş durumdur. Geri aramada veri
alabilirsiniz mutated/updated.


1
Bu geri aramayı herhangi bir işlevi geçmek için de kullanabilirsiniz initMap(), örneğin
Dende

Gitme zamanı! Sonunda sorunumu çözdüm. Çok teşekkürler.
Ahmet Halilović

12

SetSatate zaman uyumsuz bir işlev olduğundan, durumu böyle bir geri arama olarak konsolide etmeniz gerekir.

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

7

setState()bileşeni her zaman hemen güncellemiyor. Güncellemeyi toplu olarak veya daha sonrasına erteleyebilir. Bu, bu durumu okumayı setState()potansiyel bir tuzağa düşürdükten hemen sonra yapar . Bunun yerine, güncelleme uygulandıktan sonra her ikisinin de etkinleşmesi garanti edilen componentDidUpdatebir setStatecallback ( setState(updater, callback)) kullanın . Durumu önceki duruma göre ayarlamanız gerekiyorsa, aşağıdaki güncelleyici bağımsız değişkenini okuyun.

setState()shouldComponentUpdate()false döndürmediği sürece her zaman bir yeniden işleme yol açar . Değişken nesneler kullanılıyorsa ve koşullu oluşturma mantığı uygulanamıyorsa shouldComponentUpdate(), setState()yalnızca yeni durum önceki durumdan farklı olduğunda arama, gereksiz yeniden oluşturmaları önleyecektir.

İlk argüman, imzaya sahip bir güncelleyici işlevidir:

(state, props) => stateChange

statedeğişiklik uygulandığı sırada bileşen durumuna bir referanstır. Doğrudan mutasyona uğratılmamalıdır. Bunun yerine, değişiklikler durum ve proplardan gelen girdiye dayalı olarak yeni bir nesne oluşturarak temsil edilmelidir. Örneğin, durumdaki bir değeri props.step ile artırmak istediğimizi varsayalım:

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

2

Durumun güncellenip güncellenmediğini izlemek istiyorsanız, aynı şeyi yapmanın başka bir yolu da

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

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

Bu şekilde, hata ayıklama için durumu her güncellemeye çalıştığınızda "_stateUpdated" yöntemini çağırabilirsiniz.


1

setState()zaman uyumsuzdur. Durumun güncellenip güncellenmediğini doğrulamanın en iyi yolu, componentDidUpdate()bir console.log(this.state.boardAddModalShow)after koymamaktır this.setState({ boardAddModalShow: true }).

React Docs'a göre

SetState () 'i, bileşeni güncellemek için anında bir komut olarak değil, bir istek olarak düşünün. Daha iyi algılanan performans için React bunu geciktirebilir ve ardından tek geçişte birkaç bileşeni güncelleyebilir. React, durum değişikliklerinin hemen uygulanacağını garanti etmez


1

React Docs'a göre

React, durum değişikliklerinin hemen uygulanacağını garanti etmez. Bu, setState () çağrıldıktan hemen sonra this.state'in okunmasını bir potansiyel yapar pitfallve doğası gereği potansiyel olarak existingdeğeri döndürebilir async. Bunun yerine, setState işlemi başarılı olduktan hemen sonra çalıştırılan componentDidUpdatebir setStategeri çağırma veya kullanın.Genel olarak componentDidUpdate()bunun yerine böyle bir mantık kullanmanızı öneririz .

Misal:

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);


1

Bunu kancalarla yapmaya çalışan herkes için ihtiyacınız var 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>
  </>
}

Çıktı:

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

-1

kodu çalıştırırken ve konsolda çıktımı kontrol ederken, bunun tanımsız olduğunu gösteriyor. Etrafı araştırdıktan ve benim için işe yarayan bir şey bulduktan sonra.

componentDidUpdate(){}

Bu yöntemi, constructor () 'dan sonra koduma ekledim. react yerel iş akışının yaşam döngüsünü inceleyin.

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


-2
 this.setState({
    isMonthFee: !this.state.isMonthFee,
  }, () => {
    console.log(this.state.isMonthFee);
  })

2
Bu tam olarak en çok oylanan yanıtın açıkladığı şeydir, ancak herhangi bir açıklama yapılmadan ve 3 yıl geç. Ekleyeceğiniz alakalı bir şey olmadıkça
Emile Bergeron

-2

Evet çünkü setState zaman uyumsuz bir işlevdir. Set durumunu yazdıktan hemen sonra durumu ayarlamanın en iyi yolu, Object.assign'ı şu şekilde kullanmaktır: Örneğin, isValid özelliğini true olarak ayarlamak istiyorsanız, bunu böyle yapın


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


Bu satırı yazdıktan hemen sonra güncellenmiş duruma erişebilirsiniz.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.