เมื่อใดจึงจะใช้ React setState callback


191

เมื่อสถานะองค์ประกอบของการตอบสนองเปลี่ยนแปลงวิธีการแสดงผลจะถูกเรียก ดังนั้นสำหรับการเปลี่ยนแปลงสถานะใด ๆ การดำเนินการสามารถทำได้ในร่างกายวิธีการแสดงผล มีกรณีการใช้งานเฉพาะสำหรับการโทรกลับ setState หรือไม่?


4
ขณะนี้ยังไม่ชัดเจนในสิ่งที่คุณถาม คุณสามารถใส่รหัสได้ไหม
Davin Tryon

2
การเรียกกลับ setState มีไว้สำหรับทุกสิ่งที่คุณต้องการทำหลังจากที่รัฐได้กำหนด DEFINITELY แล้ว เนื่องจาก setState เป็น async ถ้าคุณต้องการเรียก fx และต้องแน่ใจว่าสถานะใหม่ถูกโหลดนั่นคือสิ่งที่การติดต่อกลับใช้สำหรับ
Jayce444

3
กรณีการใช้งานสำหรับการเรียกกลับ setState ค่อนข้างชัดเจน คุณใช้เมื่อคุณต้องการให้ฟังก์ชันเรียกใช้หลังจากสถานะ SPECIFIC ได้รับการปรับปรุง หากคุณใส่ฟังก์ชั่นนี้ render()แทนมันจะทำงานทุกครั้งที่มีการอัพเดทสถานะใด ๆ ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ สิ่งนี้จะทำให้โค้ดของคุณอ่านน้อยลงและใช้ตรรกะได้
M3RS

คำตอบ:


225

ใช่มีตั้งแต่การsetStateทำงานในasynchronousทาง หมายความว่าหลังจากที่เรียกตัวแปรจะไม่เปลี่ยนแปลงทันที ดังนั้นหากคุณต้องการดำเนินการทันทีหลังจากตั้งค่าสถานะในตัวแปรสถานะแล้วส่งคืนผลลัพธ์การเรียกกลับจะมีประโยชน์setStatethis.state

ลองพิจารณาตัวอย่างด้านล่าง

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

รหัสข้างต้นอาจไม่ทำงานตามที่คาดไว้เนื่องจากtitleตัวแปรอาจไม่ได้กลายพันธุ์ก่อนที่จะทำการตรวจสอบความถูกต้อง ตอนนี้คุณอาจสงสัยว่าเราสามารถทำการตรวจสอบความถูกต้องในrender()ฟังก์ชั่นของตัวเอง แต่มันจะดีกว่าและเป็นวิธีที่สะอาดกว่าถ้าเราสามารถจัดการสิ่งนี้ในฟังก์ชั่น changeTitle ได้เองเพราะนั่นจะทำให้รหัสของคุณเป็นระเบียบ

ในกรณีนี้การโทรกลับมีประโยชน์

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

อีกตัวอย่างหนึ่งคือเมื่อคุณต้องการdispatchและการกระทำเมื่อมีการเปลี่ยนแปลงสถานะ คุณจะต้องทำมันในการติดต่อกลับและไม่ใช่สิ่งrender()ที่มันจะถูกเรียกว่าการแสดงผลซ้ำทุกครั้งที่เกิดขึ้นและด้วยเหตุนี้สถานการณ์ดังกล่าวจำนวนมากเป็นไปได้ที่คุณจะต้องโทรกลับ

อีกกรณีหนึ่งคือ API Call

กรณีอาจเกิดขึ้นเมื่อคุณจำเป็นต้องทำการเรียก API ตามการเปลี่ยนแปลงสถานะเฉพาะถ้าคุณทำเช่นนั้นในวิธีการแสดงผลมันจะถูกเรียกในทุกonStateการเปลี่ยนแปลงการแสดงผลหรือเนื่องจาก Prop บางส่วนส่งผ่านไปยังการChild Componentเปลี่ยนแปลง

ในกรณีนี้คุณต้องการใช้ a setState callbackเพื่อส่งผ่านค่าสถานะที่อัพเดตไปยังการเรียก API

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....

3
ฉันเข้าใจว่ามันเป็นแบบอะซิงโครนัสในธรรมชาติ คำถามของฉันก็จะมีบางสิ่งบางอย่างที่เฉพาะเจาะจงว่ามีเพียงการเรียกกลับ setState สามารถนำมาใช้สำหรับการที่อาจจะทำให้ร่างกายวิธีการอาจไม่สนับสนุน (บางสิ่งบางอย่างที่นอกเหนือจากที่ขอบอกว่ารหัสอ่านได้ง่ายขึ้น.)
Sahil เชน

@SahilJain Validation เป็นตัวอย่างที่ถูกต้องคุณไม่ต้องการจัดการมันในฟังก์ชั่น render () เพราะมันจะถูกเรียกทุกครั้งที่คุณทำการเปลี่ยนแปลงใน render () คุณจะต้องเรียกมันเฉพาะเมื่อมีการเปลี่ยนแปลงอินพุตเท่านั้น ในฟังก์ชั่นของตัวเอง
Shubham Khatri

ตอบโต้ห้ามไม่ให้เปลี่ยนสถานะในระหว่างการเรนเดอร์ .. ดังนั้นสิทธิในการใส่การตรวจสอบความถูกต้องในการเรียกกลับ
webdeb

if (this.title.length === 0) {ควรจะthis.state.title.lengthใช่มั้ย
Dmitry Minkovsky

4
กรณีใช้งานครั้งแรกอาจไม่ใช่ความคิดที่ดี setState ทริกเกอร์การเรียกกลับหลังจากแสดงอีกครั้งดังนั้นคุณทำให้เกิดการแสดงผลสองครั้งโดยไม่มีเหตุผลที่ดี นี่คือจุดประสงค์ของการโต้แย้งฟังก์ชัน (updater) คุณสามารถเรียกใช้setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)และการเปลี่ยนแปลงจะสแต็ค ไม่จำเป็นต้องมีการแสดงซ้ำ
R Esmond

47
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});

14
ขอขอบคุณสำหรับข้อมูลโค้ดนี้ซึ่งอาจให้ความช่วยเหลือแบบ จำกัด และทันที คำอธิบายที่เหมาะสมมากจะเพิ่มมูลค่าในระยะยาวด้วยการแสดงเหตุผลนี้เป็นทางออกที่ดีในการแก้ไขปัญหาและจะทำให้มันมีประโยชน์มากขึ้นให้กับผู้อ่านในอนาคตกับอื่น ๆ คำถามที่คล้ายกัน โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงข้อสมมติที่คุณได้ทำไว้
Machavity

1
เมื่อคุณต้องการเรียกฟังก์ชั่นหลังจากเปลี่ยนสถานะคุณสามารถใช้วิธีการ
Araz Babayev

จะเป็นอย่างไรถ้าคุณต้องการตั้งค่าสถานะรูพรุนหลายอย่างเช่นชื่อ, ชื่อและอื่น ๆ
Sumanth Varada

44

1. usecase ที่เข้ามาในใจของฉันคือการapiโทรซึ่งไม่ควรเข้าสู่การเรนเดอร์เพราะมันจะทำงานเพื่อeachการเปลี่ยนแปลงสถานะ และการเรียก API ควรดำเนินการเฉพาะเมื่อมีการเปลี่ยนแปลงสถานะพิเศษเท่านั้นและไม่ควรแสดงผลทุกครั้ง

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

ดังนั้นสำหรับการเปลี่ยนแปลงสถานะใด ๆ การดำเนินการสามารถทำได้ในร่างกายวิธีการแสดงผล

การปฏิบัติที่ไม่ดีมากเพราะ - วิธีการrenderควรบริสุทธิ์หมายความว่าไม่มีการดำเนินการเปลี่ยนแปลงสถานะการเรียกใช้ api เพียงรวมมุมมองของคุณแล้วส่งคืน การดำเนินการควรกระทำในบางเหตุการณ์เท่านั้น Render ไม่ใช่เหตุการณ์ แต่componentDidMountเป็นตัวอย่าง


25

พิจารณาการเรียก setState

this.setState({ counter: this.state.counter + 1 })

IDEA

setState อาจถูกเรียกในฟังก์ชั่น async

thisดังนั้นคุณจึงไม่สามารถพึ่งพา หากการเรียกข้างต้นถูกสร้างขึ้นภายในฟังก์ชั่น async thisจะอ้างถึงสถานะขององค์ประกอบ ณ เวลานั้น แต่เราคาดว่าสิ่งนี้จะอ้างถึงคุณสมบัติภายในสถานะ ณ เวลา setState โทรหรือเริ่มต้นของงาน async และเป็นงานที่เรียก async ดังนั้นคุณสมบัติที่อาจมีการเปลี่ยนแปลงในเวลาที่ถูก ดังนั้นจึงไม่น่าเชื่อถือในการใช้thisคำสำคัญเพื่ออ้างถึงคุณสมบัติบางอย่างของรัฐดังนั้นเราจึงใช้ฟังก์ชั่นการโทรกลับที่มีอาร์กิวเมนต์เป็น nextState และอุปกรณ์ประกอบฉากซึ่งหมายความว่าเมื่องาน async เสร็จสิ้นและถึงเวลาที่จะปรับปรุงสถานะ ยังไม่ได้เริ่ม สร้างความมั่นใจในความน่าเชื่อถือว่า nextState จะไม่เสียหาย

รหัสผิด: จะนำไปสู่ความเสียหายของข้อมูล

this.setState(
   {counter:this.state.counter+1}
 );

รหัสที่ถูกต้องด้วย setState มีฟังก์ชั่นโทรกลับ:

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

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

ฉันพยายามอธิบายใน codepen ที่นี่ CODE PEN

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.