ฉันจะรีเซ็ตส่วนประกอบการตอบสนองรวมถึงสถานะที่สามารถเข้าถึงได้ทุกสวิทช์ได้อย่างไร


98

บางครั้งฉันจะมีส่วนประกอบของปฏิกิริยาที่มีสภาพตามแนวคิดซึ่งฉันต้องการรีเซ็ต พฤติกรรมในอุดมคติจะเทียบเท่ากับการลบส่วนประกอบเก่าและอ่านส่วนประกอบใหม่ที่บริสุทธิ์

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

มี API หรือรูปแบบในการทำสิ่งนี้หรือไม่?

แก้ไข: ฉันทำตัวอย่างเล็กน้อยเพื่อแสดงให้เห็นถึงthis.replaceState(this.getInitialState())แนวทางและเปรียบเทียบกับthis.setState(this.getInitialState())แนวทาง: jsfiddle - replaceStateมีประสิทธิภาพมากขึ้น

คำตอบ:


217

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

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

ไม่มีทางลัดในการรีเซ็ตสถานะท้องถิ่นของส่วนประกอบแต่ละรายการ


1
ด้วยความอยากรู้อยากเห็นเมื่อคุณพูดว่า 'องค์ประกอบจะถูกโยนทิ้งและสร้างขึ้นตั้งแต่ต้น' คุณหมายความว่า DOM เสมือนจะถูกโยนทิ้งและสร้างขึ้นตั้งแต่ต้น แต่การอัปเดต DOM จะยังคงเกิดขึ้นตามอัลกอริทึมต่าง
nimgrg

1
@nimgrg ไม่องค์ประกอบ DOM จริงจะถูกสร้างขึ้นใหม่เช่นกัน (DOM เสมือนถูกสร้างขึ้นใหม่ในทุกการเรนเดอร์ดังนั้นหากคุณต้องการเก็บ DOM จริงก็อย่าตั้งค่าkeyในกรณีนี้)
โซฟีอัลเพิร์ต

3
@EamonNerbonne บน React 0.8 คีย์จะใช้เพื่อแยกความแตกต่างระหว่างองค์ประกอบพี่น้องในอาร์เรย์เท่านั้นและถูกละเว้นที่รูท ดูgithub.com/facebook/react/issues/590
Sophie Alpert

หมายเหตุreplaceState()และgetInitialState()ทั้งคู่เลิกใช้แล้วใน reactjs สไตล์คลาส ES6 ใหม่ ใช้this.setState(this._getInitialState())แทน นอกจากนี้คุณไม่สามารถตั้งชื่อฟังก์ชั่นเริ่มต้นสถานะของคุณเองได้getInitialState()- ตอบสนองจะส่งคำเตือน - เรียกสิ่งอื่นใดและทำอย่างชัดเจนstate = this._getInitialState()ในระดับบนสุดของคลาส
thom_nic

2
มีวิธีดำเนินการจากด้านในของส่วนประกอบโดยไม่ต้องให้ด้านนอกผ่านเสาหลักหรือไม่?
trusktr

14

คุณควรหลีกเลี่ยงreplaceStateและใช้setStateแทน

เอกสารระบุว่าreplaceState"อาจถูกลบออกทั้งหมดใน React เวอร์ชันอนาคต" ฉันคิดว่ามันจะถูกลบออกไปอย่างแน่นอนที่สุดเพราะreplaceStateไม่ได้ล้อเล่นกับปรัชญาของ React ช่วยอำนวยความสะดวกในการทำให้ส่วนประกอบ React เริ่มรู้สึกว่ามีดสวิส -y สิ่งนี้จะต่อต้านการเติบโตตามธรรมชาติขององค์ประกอบปฏิกิริยาที่มีขนาดเล็กลงและถูกสร้างขึ้นตามวัตถุประสงค์

ในการตอบสนองหากคุณต้องทำผิดเกี่ยวกับลักษณะทั่วไปหรือความเชี่ยวชาญ: มุ่งเป้าไปที่ความเชี่ยวชาญ ในฐานะที่เป็นข้อพิสูจน์ต้นไม้สถานะสำหรับส่วนประกอบของคุณควรมีพาร์ซิเมนต์ที่แน่นอน (คุณควรฝ่าฝืนกฎนี้อย่างมีรสนิยมหากคุณกำลังนั่งร้านผลิตภัณฑ์ใหม่ที่ตีตราสินค้า)

อย่างไรก็ตามนี่คือวิธีที่คุณทำ คล้ายกับคำตอบของ Ben (ยอมรับ) ข้างต้น แต่เป็นแบบนี้:

this.setState(this.getInitialState());

นอกจากนี้ (เช่นที่ Ben กล่าว) ในการรีเซ็ต "สถานะเบราว์เซอร์" คุณต้องลบโหนด DOM นั้นออก ควบคุมพลังของ vdom และใช้keyเสาใหม่สำหรับส่วนประกอบนั้น การแสดงผลใหม่จะแทนที่การขายส่งส่วนประกอบนั้น

อ้างอิง: https://facebook.github.io/react/docs/component-api.html#replacestate


2
สิ่งนี้จะไม่ทำงานหากสถานะปัจจุบันมีคุณสมบัติใด ๆ ที่ไม่ได้อยู่ในสถานะเริ่มต้น แม้ว่าฉันจะไม่เชื่อว่านั่นเป็น "สถานะ" ที่ยิ่งใหญ่ที่จะเกิดขึ้นเว้นแต่คุณจะสามารถป้องกันได้ แต่ฉันก็ต้องการหลีกเลี่ยงความแตกแยกที่น่าประหลาดใจ ฉันจะโอเคกับการรีเซ็ตที่ขัดข้องในบางกรณี แต่ไม่ใช่การรีเซ็ตที่ทำให้สถานะเสียหายเล็กน้อย
Eamon Nerbonne

ไม่แน่ใจว่าฉันทำตาม คุณกำลังบอกว่าสิ่งนี้ไม่เทียบเท่ากับthis.replaceState? เพราะมันเป็น
wle8300

1
@ williamle8300 สิ่งเหล่านี้จะไม่เทียบเท่าหากมีการเพิ่มคุณสมบัติใหม่ในสถานะที่ใดที่หนึ่งในวงจรชีวิตของส่วนประกอบระหว่างการโทรไปยังgetInitialState()(พูดในตัวจัดการ onClick) getInitialState()ในกรณีนี้ว่าทรัพย์สินใหม่จะยังคงอยู่ในปัจจุบันหลังจากที่ 2
Graham

@Graham ฉันเชื่อว่าเป็นการปฏิบัติที่ไม่ดีในการแนะนำสถานะใหม่ให้กับส่วนประกอบที่ยังไม่ได้ประกาศgetInitialStateไว้ เหมือนกับการประกาศตัวแปรทั้งหมดของคุณในฟังก์ชัน JS ที่ด้านบนสุดของฟังก์ชัน หมายเหตุด้านข้าง: โซลูชันของ Ben Alpert นั้นใกล้เคียงกับของฉัน ... และเขาเป็นผู้ดูแล React อย่างเป็นทางการ!
wle8300

1
ฉันกลัวว่าฟังก์ชัน getInitialState () และด้วยเหตุนี้คำตอบจึงเลิกใช้งาน การอัปเดตจะดี
Martin R.

11

การเพิ่มkeyแอตทริบิวต์ให้กับองค์ประกอบที่คุณต้องการเริ่มต้นใหม่จะโหลดซ้ำทุกครั้งที่propsหรือstateเชื่อมโยงกับการเปลี่ยนแปลงองค์ประกอบ

คีย์ = {วันที่ใหม่ (). getTime ()}

นี่คือตัวอย่าง:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}

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