ตอบสนอง setState ไม่ได้อัปเดตสถานะ


99

ฉันมีสิ่งนี้:

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 เป็นเพียงอาร์เรย์ของตัวเลข[1, 5, 9]เช่น แต่this.state.dealersOverallTotalไม่ได้ให้ผลรวมที่ถูกต้อง แต่total? ฉันยังใช้เวลาหน่วงเวลาเพื่อดูว่าวิธีนี้ช่วยแก้ปัญหาได้หรือไม่ ชัดเจนหรือควรโพสต์โค้ดเพิ่มเติม



@ อัสรันไชโย !!
หนอน

นอกจากนี้สิ่งที่ถูกกล่าวในคำตอบที่คุณกำลังเข้าสู่ระบบอย่างชัดเจนค่าของรัฐก่อนที่setStateคุณจะโทร
Felix Kling

1
@FelixKling ไม่ฉันเรียกสิ่งนี้รัฐหลังจากที่ฉันตั้งค่า ฉันกำลังบันทึกตัวแปรมาก่อน เปล่า?
หนอน

เนื่องจากการหมดเวลาของคุณsetStateจะถูกดำเนินการหลังจากที่คุณเข้าสู่ระบบ ฉันคิดว่าสิ่งที่คุณตั้งใจจะทำในการดีบักคือการวางconsole.logส่วนไว้ในระยะหมดเวลาและsetStateภายนอก
Fabian Schultz

คำตอบ:


192

setState()โดยปกติจะเป็นแบบอะซิงโครนัสซึ่งหมายความว่าในขณะที่คุณconsole.logอยู่ในสถานะจะยังไม่ได้รับการอัปเดต ลองใส่บันทึกในการเรียกกลับของsetState()วิธีการ ดำเนินการหลังจากการเปลี่ยนแปลงสถานะเสร็จสมบูรณ์:

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

2
นอกจากนั้น, OP อย่างชัดเจนบันทึกมูลค่ารัฐก่อนที่setStateพวกเขาเรียกว่า
Felix Kling

สิ่งนี้ใช้ได้กับฉันเช่นกันในอดีตฉันเคยใช้สิ่งนี้: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'แต่ด้วยเหตุผลบางอย่างมันก็ไม่น่าเป็นห่วง อีกต่อไปเมื่อฉันอัปเดตโค้ดตามที่อธิบายไว้ข้างต้นมันใช้งานได้ทำไม?
Jozcar

1
@Jozcar ควรใช้งานได้ด้วยไวยากรณ์ไม่ถูกต้อง (ไม่มีวงเล็บ):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTlโปรดบอกฉันว่าฉันควรทำอย่างไรเพื่อกำจัดปัญหานี้
Johncy

1
ฉันลืมไปแล้วว่ามันเป็นการโทรแบบไม่ซิงค์และทำการเปลี่ยนแปลงรหัสที่เป็นไปได้ทั้งหมดยกเว้นอันนี้และที่นี่คุณช่วยสมองของฉันจากการเผาไหม้ ขอบคุณ
มิ้ม M

17

setState เป็นแบบอะซิงโครนัส คุณสามารถใช้วิธีการโทรกลับเพื่อรับสถานะที่อัปเดต

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

12

ใช้ async / await

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

8

การsetState()ดำเนินการเป็นแบบอะซิงโครนัสและด้วยเหตุนี้คุณconsole.log()จะถูกดำเนินการก่อนที่จะsetState()กลายพันธุ์ค่าและด้วยเหตุนี้คุณจึงเห็นผลลัพธ์

ในการแก้ปัญหาให้บันทึกค่าในฟังก์ชันเรียกกลับของsetState()เช่น:

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

JavaScript ซิงโครนัสเสมอ
Santosh Singh

1
@santoshsingh คุณมีความเข้าใจผิด การเรียก API การหมดเวลาทั้งหมดเกิดขึ้นแบบอะซิงโครนัส
Shubham Khatri

ดังที่คุณได้กล่าวไว้ข้างต้นว่าจาวาสคริปต์เป็นแบบอะซิงโครนัส --- ไม่ถูกต้อง ซิงโครนัสส่วนใหญ่และสำหรับกรณีเป็นแบบอะซิงโครนัส stackoverflow.com/questions/2035645/…
Santosh Singh

@santoshsingh. โอ้นั่นเป็นความผิดพลาดในส่วนของฉัน สร้างประโยคไม่ถูกต้อง
Shubham Khatri

การใช้การโทรกลับอย่างชาญฉลาดเพื่อให้แน่ใจว่าสถานะได้รับการอัปเดตก่อนการโทรครั้งต่อไป!
user1204214

7

ในกรณีที่มีตะขอคุณควรใช้useEffectตะขอ

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

setFruit('Apple');

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

เยี่ยมมากมันใช้ได้กับ useEffect แต่ทำไมต้องมี?
alex351

useEffectทำงานในทุก ๆ re-render และหากรายการที่ส่งผ่านไปยังอาร์เรย์จะมีการเปลี่ยนแปลงสถานะของตัวแปร sand ดังนั้นเมื่อผลไม้เปลี่ยนไปและแสดงผลส่วนประกอบอีกครั้ง useEffect นั้นจะทำงาน
Siraj Alam

ฉันเรียกใช้ setFruit และ console.log ผลไม้นอก useEffect และไม่เปลี่ยนแปลง : /
alex351

4

setstate เป็นแบบอะซิงโครนัสในการตอบสนองดังนั้นหากต้องการดูสถานะที่อัปเดตในคอนโซลให้ใช้การเรียกกลับตามที่แสดงด้านล่าง (ฟังก์ชัน Callback จะดำเนินการหลังจากการอัปเดต setstate)

ป้อนคำอธิบายภาพที่นี่

วิธีการด้านล่างนี้ "ไม่แนะนำ" แต่เพื่อความเข้าใจหากคุณเปลี่ยนสถานะโดยตรงคุณจะเห็นสถานะที่อัปเดตในบรรทัดถัดไป ขอย้ำว่า "ไม่แนะนำ"

ป้อนคำอธิบายภาพที่นี่


ขอบคุณที่เป็นอย่างนี้คุณต้องตั้งค่าตัวแปรโดยตรง
notacorn


1

ฉันมีสถานการณ์เดียวกันกับโค้ดที่ซับซ้อนและไม่มีอะไรจากคำแนะนำที่มีอยู่สำหรับฉัน

ปัญหาของฉันsetStateคือเกิดจาก func เรียกกลับซึ่งออกโดยหนึ่งในองค์ประกอบ และที่น่าสงสัยของฉันคือการโทรเกิดขึ้นพร้อมกันซึ่งทำให้ไม่สามารถsetStateตั้งค่าสถานะได้เลย

ใส่เพียงแค่ฉันมีสิ่งนี้:

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

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

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

วิธีที่ฉันมีการ "แก้ไข" มันก็จะนำdoUpdate()เข้าsetTimeoutเช่นนี้

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

ไม่เหมาะ แต่อย่างอื่นมันจะเป็นการปรับโครงสร้างที่สำคัญ


สิ่งนี้ช่วยแก้ปัญหาของฉันได้ แต่ฉันใส่ setState () ไว้ใน setTimeout () แทน ขอขอบคุณ!
thargenediad

0

ฉันมีปัญหาเมื่อตั้งค่าสถานะการตอบกลับหลายครั้ง (ใช้สถานะเริ่มต้นเสมอ) การติดตามปัญหาreact / githubนี้ใช้ได้ผลสำหรับฉัน

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

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.