คุณสามารถบังคับให้ส่วนประกอบ React ทำการแสดงซ้ำโดยไม่เรียก setState ได้หรือไม่?


690

ฉันมีวัตถุภายนอก (ไปยังส่วนประกอบ) ซึ่งสามารถสังเกตได้ที่ฉันต้องการฟังเพื่อการเปลี่ยนแปลง เมื่อวัตถุได้รับการปรับปรุงมันจะปล่อยกิจกรรมการเปลี่ยนแปลงและจากนั้นฉันต้องการที่จะแสดงส่วนประกอบอีกครั้งเมื่อตรวจพบการเปลี่ยนแปลงใด ๆ

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

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

export default class MyComponent extends React.Component {

  handleButtonClick() {
    this.render();
  }

  render() {
    return (
      <div>
        {Math.random()}
        <button onClick={this.handleButtonClick.bind(this)}>
          Click me
        </button>
      </div>
    )
  }
}

การคลิกปุ่มโทรภายในthis.render()แต่นั่นไม่ใช่สิ่งที่ทำให้เกิดการแสดงผลจริง (คุณสามารถเห็นสิ่งนี้ได้ในทางปฏิบัติเพราะข้อความที่สร้างขึ้นโดย{Math.random()}ไม่เปลี่ยนแปลง) อย่างไรก็ตามถ้าฉันเพียงแค่โทรthis.setState()แทนthis.render()มันก็ใช้ได้ดี

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


7
คำตอบที่ได้รับการยอมรับว่าเป็นโซลูชั่นที่เหมาะสมในขณะที่ส่วนที่เหลือของทุกคำตอบและความคิดเห็นหลายกับการใช้this.forceUpdate() forceUpdate()ถ้าอย่างนั้นจะเป็นการดีถ้าจะบอกว่าคำถามยังไม่ได้คำตอบหรือคำตอบที่เหมาะสม?
adi

6
คำตอบที่ยกเว้นได้ตอบคำถามของฉันในเวลานั้น เทคนิคนี้เป็นคำตอบที่ฉันต้องการหรือไม่และฉันก็ยังคิดว่าคำตอบที่ถูกต้อง คำตอบอื่น ๆ ที่ฉันคิดว่าเป็นข้อมูลเสริมที่ดีสำหรับผู้ที่มีคำถามเดียวกันที่ต้องระวัง
ฟิลิปวอลตัน

สิ่งที่น่าสนใจคือคุณไม่จำเป็นต้องมีอะไรเลยนอกจากการกำหนดค่าเริ่มต้นให้กับวัตถุธรรมดาแล้วเรียก this.setState ({}) เพียงแค่เรียกการเรนเดอร์ใหม่ ปฏิกิริยานั้นยอดเยี่ยม แต่ก็แปลก ๆ ดังนั้นคุณสามารถวนลูปโดยตรงผ่านข้อมูลร้านค้าเมื่อทริกเกอร์การเปลี่ยนแปลงโดยไม่มีการวางท่อเพิ่มเติมหรือกังวลเกี่ยวกับข้อมูลต่ออินสแตนซ์ของส่วนประกอบ
Jason Sebring

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

คำตอบ:


765

ในองค์ประกอบของคุณคุณสามารถเรียกthis.forceUpdate()เพื่อบังคับให้แสดงซ้ำ

เอกสารประกอบ: https://facebook.github.io/react/docs/component-api.html


169
อีกวิธีคือ this.setState (this.state);
kar

25
การใช้ forceupdate นั้นหมดกำลังใจโปรดดูคำตอบสุดท้าย
Varand Pezeshkian

42
แม้ว่าthis.forceUpdate()การแก้ปัญหาของผู้ถามจะไม่ใช่วิธีที่ดีมาก แต่เป็นคำตอบที่ถูกต้องสำหรับคำถามที่โพสต์ในชื่อเรื่อง ในขณะที่ควรหลีกเลี่ยงโดยทั่วไปมีสถานการณ์เมื่อ forceUpdate เป็นทางออกที่ดี
ArneHugo

8
@kar ที่จริงแล้วตรรกะเพิ่มเติมสามารถนำไปใช้ในshouldComponentUpdate()การแก้ปัญหาของคุณไร้ประโยชน์
Qwerty

4
เกินจำนวนสแต็กการโทรสูงสุด
IntoTheDeep

326

forceUpdateควรหลีกเลี่ยงเพราะมันเบี่ยงเบนไปจากความคิดของ React เอกสารตอบโต้อ้างอิงตัวอย่างของเวลาที่forceUpdateอาจใช้:

ตามค่าเริ่มต้นเมื่อสถานะของอุปกรณ์ประกอบฉากของคุณเปลี่ยนส่วนประกอบของคุณจะแสดงผลอีกครั้ง อย่างไรก็ตามหากการเปลี่ยนแปลงเหล่านี้โดยนัย (เช่น: ข้อมูลลึกภายในการเปลี่ยนแปลงวัตถุโดยไม่เปลี่ยนวัตถุเอง) หรือหากวิธีการเรนเดอร์ () ของคุณขึ้นอยู่กับข้อมูลอื่น ๆ คุณสามารถบอกได้ว่าต้องการเรียกใช้เรนเดอร์อีกครั้ง forceUpdate ()

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

โดยปกติคุณควรพยายามหลีกเลี่ยงการใช้ forceUpdate () ทั้งหมดและอ่านจาก this.props และ this.state ใน render () เท่านั้น สิ่งนี้ทำให้องค์ประกอบของคุณ "บริสุทธิ์" และแอปพลิเคชันของคุณง่ายขึ้นและมีประสิทธิภาพมากขึ้น forceUpdate ()

การเปลี่ยนคีย์ขององค์ประกอบที่คุณต้องการให้แสดงซ้ำจะทำงานได้ ตั้งค่าคีย์ prop ในองค์ประกอบของคุณผ่านสถานะและจากนั้นเมื่อคุณต้องการอัปเดตกำหนดสถานะให้มีคีย์ใหม่

<Element key={this.state.key} /> 

จากนั้นมีการเปลี่ยนแปลงเกิดขึ้นและคุณรีเซ็ตคีย์

this.setState({ key: Math.random() });

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

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

หมายเหตุ 1-9-2019:

ด้านบน (เปลี่ยนคีย์) จะแทนที่องค์ประกอบอย่างสมบูรณ์ หากคุณพบว่าตัวเองอัปเดตรหัสเพื่อทำการเปลี่ยนแปลงเกิดขึ้นคุณอาจมีปัญหาในรหัสของคุณ การใช้Math.random()คีย์จะสร้างองค์ประกอบอีกครั้งพร้อมกับการแสดงผลแต่ละครั้ง ฉันจะไม่แนะนำให้อัปเดตคีย์เช่นนี้เนื่องจากการตอบสนองใช้คีย์เพื่อกำหนดวิธีที่ดีที่สุดในการแสดงสิ่งใหม่


16
ฉันสนใจที่จะทราบว่าเหตุใดจึงมีการลงคะแนนเสียง ฉันพยายามต่อสู้กับผู้อ่านหน้าจอเพื่อตอบสนองต่อการแจ้งเตือนเพลงและนี่เป็นเทคนิคเดียวที่ฉันพบว่าทำงานได้อย่างน่าเชื่อถือ หากคุณมีบางอย่างใน UI ของคุณที่สร้างการแจ้งเตือนเดียวกันทุกครั้งที่มีการคลิกโดยค่าเริ่มต้นการตอบสนองจะไม่แสดง DOM อีกครั้งดังนั้นโปรแกรมอ่านหน้าจอจะไม่ประกาศการเปลี่ยนแปลง การตั้งค่าคีย์เฉพาะทำให้ใช้งานได้ อาจเป็นเพราะการลงคะแนนเสียงยังคงเกี่ยวข้องกับการตั้งค่าสถานะ แต่การบังคับให้เรนเดอร์กลับไปที่ DOM โดยการตั้งค่าคีย์นั้นเป็นสีทอง!
Martin Bayly

2
ฉันชอบคำตอบนี้มากเพราะ - 1: การใช้ forceupdate () ไม่ได้รับการสนับสนุนและ 2: วิธีนี้มีประโยชน์มากสำหรับส่วนประกอบบุคคลที่ 3 ซึ่งคุณติดตั้งผ่านทาง NPM ซึ่งหมายความว่าไม่ใช่องค์ประกอบของคุณเอง เช่น React-resizable-and-movable เป็นองค์ประกอบของบุคคลที่สามที่ฉันใช้ แต่ไม่ได้ตอบสนองต่อ setstate ของส่วนประกอบของฉัน นี่เป็นทางออกที่ดี
Varand Pezeshkian

81
keyนี่คือการสับและการละเมิดของ ครั้งแรกมันเป็นความตั้งใจที่ชัดเจน ผู้อ่านรหัสของคุณจะต้องทำงานอย่างหนักเพื่อทำความเข้าใจว่าทำไมคุณจึงใช้keyวิธีนี้ forceUpdateประการที่สองนี้ไม่บริสุทธิ์มากกว่า React "บริสุทธิ์" หมายความว่าการนำเสนอแบบภาพของส่วนประกอบของคุณขึ้นอยู่กับสถานะของมัน 100% ดังนั้นหากคุณเปลี่ยนสถานะใด ๆ ก็จะอัปเดต อย่างไรก็ตามหากคุณมีวัตถุที่ซ้อนกันอย่างลึกล้ำ (สถานการณ์ที่forceUpdateเอกสารอ้างอิงถึงเหตุผลในการใช้งาน) จากนั้นการใช้forceUpdateจะทำให้ชัดเจน ประการที่สามMath.random()คือ…แบบสุ่ม ในทางทฤษฎีมันสามารถสร้างตัวเลขสุ่มที่เหมือนกัน
atomkirk

8
@xtraSimplicity ฉันไม่สามารถตกลงได้ว่าสิ่งนี้สอดคล้องกับวิธีการตอบสนองของการทำสิ่งต่าง ๆ forceUpdateเป็นวิธีตอบโต้การทำเช่นนี้
Rob Grant

3
@ Robert Grant มองย้อนกลับไปฉันเห็นด้วย ความซับซ้อนที่เพิ่มขึ้นนั้นไม่คุ้มค่า
XtraSimplicity

80

ที่จริงแล้วforceUpdate()เป็นเพียงการแก้ปัญหาที่ถูกต้องsetState()อาจไม่ได้เรียกอีกครั้งทำให้ถ้าตรรกะเพิ่มเติมจะดำเนินการในหรือเมื่อมันก็ผลตอบแทนshouldComponentUpdate()false

forceUpdate ()

โทรศัพท์forceUpdate()จะทำให้เกิดการที่จะเรียกว่าในส่วนของการกระโดดข้ามrender() มากกว่า...shouldComponentUpdate()

setState ()

setState()จะเรียกการเรนเดอร์ใหม่เสมอยกเว้นว่าจะใช้ตรรกะการเรนเดอร์ตามshouldComponentUpdate()เงื่อนไข มากกว่า...


forceUpdate() สามารถเรียกได้จากภายในองค์ประกอบของคุณโดย this.forceUpdate()


Hooks: ฉันจะบังคับให้ส่วนประกอบแสดงผลอีกครั้งด้วย hooks ใน React ได้อย่างไร


BTW: คุณกำลังกลายพันธุ์รัฐหรือคุณสมบัติที่ซ้อนกันของคุณไม่ได้เผยแพร่?


1
สิ่งหนึ่งที่น่าสนใจที่ควรทราบคือการประเมินสถานะภายนอก setState เช่น this.state.foo = 'bar' จะไม่เรียกวิธีการแสดงผลรอบการทำงาน
lfender6445

4
@ lfender6445 การกำหนดสถานะโดยตรงกับthis.stateด้านนอกของตัวสร้างควรโยนข้อผิดพลาด อาจไม่ได้ทำในปี 2559 แต่ฉันค่อนข้างแน่ใจว่าจะทำตอนนี้
Tyler

ฉันได้เพิ่มลิงก์บางส่วนเพื่อแก้ไขการมอบหมายโดยตรง
Qwerty

36

ฉันหลีกเลี่ยงforceUpdateโดยทำตาม

ผิดทาง : อย่าใช้ดัชนีเป็นกุญแจ

this.state.rows.map((item, index) =>
   <MyComponent cell={item} key={index} />
)

วิธีที่ถูกต้อง : ใช้รหัสข้อมูลเป็นกุญแจอาจเป็น guid และอื่น ๆ

this.state.rows.map((item) =>
   <MyComponent item={item} key={item.id} />
)

ดังนั้นการปรับปรุงโค้ดดังกล่าวจะทำให้องค์ประกอบของคุณไม่เหมือนใครและแสดงผลตามธรรมชาติ


this.state.rows.map((item) => <MyComponent item={item} key={item.id} /> )
Tal

ขอบคุณมากที่ผลักดันฉันไปในทิศทางที่ถูกต้อง การใช้ดัชนีเป็นกุญแจนั้นเป็นปัญหาของฉันจริงๆ
RoiEX

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

34

เมื่อคุณต้องการให้คอมโพเนนต์ React สองตัวสื่อสารกันซึ่งไม่สัมพันธ์กับความสัมพันธ์ (parent-child) ขอแนะนำให้ใช้Fluxหรือสถาปัตยกรรมที่คล้ายคลึงกัน

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

forceUpdate()ปกติคุณควรพยายามที่จะหลีกเลี่ยงการใช้ จากเอกสาร:

โดยปกติคุณควรพยายามหลีกเลี่ยงการใช้ forceUpdate () ทั้งหมดและอ่านจาก this.props และ this.state ใน render () เท่านั้น สิ่งนี้ทำให้แอปพลิเคชันของคุณง่ายขึ้นและมีประสิทธิภาพมากขึ้น


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

5
คำแนะนำที่แท้จริงคือการส่งผ่านข้อมูลร้านค้าไปยังอุปกรณ์ประกอบฉากและใช้สถานะส่วนประกอบสำหรับสิ่งต่างๆเช่นสถานะการเลื่อนและสิ่งเฉพาะ UI อื่น ๆ หากคุณใช้redux (ฉันแนะนำ) คุณสามารถใช้ฟังก์ชั่นการเชื่อมต่อจากreact-reduxเพื่อทำแผนที่สถานะร้านค้าโดยอัตโนมัติไปยังอุปกรณ์ประกอบฉากเมื่อใดก็ตามที่จำเป็นตามฟังก์ชั่นการทำแผนที่ที่คุณให้
Stijn de Witt

1
@AJFarkas สถานะจะถูกกำหนดให้กับข้อมูลของร้านค้าซึ่งเป็นเพียงตัวชี้ไปยังหน่วยความจำต่อไปดังนั้นหน่วยความจำจะไม่เป็นปัญหาหากคุณไม่ได้ทำการโคลน
Jason Sebring

4
"forceUpdate () ควรหลีกเลี่ยงเสมอ" ไม่ถูกต้อง เอกสารอธิบายอย่างชัดเจนว่า: "โดยปกติคุณควรพยายามหลีกเลี่ยงการใช้ forceUpdate () ทั้งหมด" มีกรณีการใช้งานที่ถูกต้องของforceUpdate
AJP

2
@AJP คุณพูดถูกต้องนั่นเป็นอคติส่วนตัวที่พูด :) ฉันได้แก้ไขคำตอบแล้ว
gcedo

18

ใช้ hooks หรือ HOC เลือกของคุณ

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

ใช้วิธีการเก็บเบ็ดเพื่อจัดการการปรับปรุงร้านค้า

interface ISimpleStore {
  on: (ev: string, fn: () => void) => void;
  off: (ev: string, fn: () => void) => void;
}

export default function useStore<T extends ISimpleStore>(store: T) {
  const [storeState, setStoreState] = useState({store});
  useEffect(() => {
    const onChange = () => {
      setStoreState({store});
    }
    store.on('change', onChange);
    return () => {
      store.off('change', onChange);
    }
  }, []);
  return storeState.store;
}

withStores HOC อัปเดตการจัดการร้านค้า

export default function (...stores: SimpleStore[]) {
  return function (WrappedComponent: React.ComponentType<any>) {
    return class WithStore extends PureComponent<{}, {lastUpdated: number}> {
      constructor(props: React.ComponentProps<any>) {
        super(props);
        this.state = {
          lastUpdated: Date.now(),
        };
        this.stores = stores;
      }

      private stores?: SimpleStore[];

      private onChange = () => {
        this.setState({lastUpdated: Date.now()});
      };

      componentDidMount = () => {
        this.stores &&
          this.stores.forEach((store) => {
            // each store has a common change event to subscribe to
            store.on('change', this.onChange);
          });
      };

      componentWillUnmount = () => {
        this.stores &&
          this.stores.forEach((store) => {
            store.off('change', this.onChange);
          });
      };

      render() {
        return (
          <WrappedComponent
            lastUpdated={this.state.lastUpdated}
            {...this.props}
          />
        );
      }
    };
  };
}

คลาส SimpleStore

import AsyncStorage from '@react-native-community/async-storage';
import ee, {Emitter} from 'event-emitter';

interface SimpleStoreArgs {
  key?: string;
  defaultState?: {[key: string]: any};
}

export default class SimpleStore {
  constructor({key, defaultState}: SimpleStoreArgs) {
    if (key) {
      this.key = key;
      // hydrate here if you want w/ localState or AsyncStorage
    }
    if (defaultState) {
      this._state = {...defaultState, loaded: false};
    } else {
      this._state = {loaded: true};
    }
  }
  protected key: string = '';
  protected _state: {[key: string]: any} = {};
  protected eventEmitter: Emitter = ee({});
  public setState(newState: {[key: string]: any}) {
    this._state = {...this._state, ...newState};
    this.eventEmitter.emit('change');
    if (this.key) {
      // store on client w/ localState or AsyncStorage
    }
  }
  public get state() {
    return this._state;
  }
  public on(ev: string, fn:() => void) {
    this.eventEmitter.on(ev, fn);
  }
  public off(ev: string, fn:() => void) {
    this.eventEmitter.off(ev, fn);
  }
  public get loaded(): boolean {
    return !!this._state.loaded;
  }
}

วิธีใช้

ในกรณีของ hooks:

// use inside function like so
const someState = useStore(myStore);
someState.myProp = 'something';

ในกรณีของ HOC:

// inside your code get/set your store and stuff just updates
const val = myStore.myProp;
myOtherStore.myProp = 'something';
// return your wrapped component like so
export default withStores(myStore)(MyComponent);

ทำให้แน่ใจ เพื่อส่งค้าของคุณเป็นซิงเกิลตันเพื่อรับประโยชน์จากการเปลี่ยนแปลงระดับโลกเช่น:

class MyStore extends SimpleStore {
  public get someProp() {
    return this._state.someProp || '';
  }
  public set someProp(value: string) {
    this.setState({...this._state, someProp: value});
  }
}
// this is a singleton
const myStore = new MyStore();
export {myStore};

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


2
this._data = {...this._data, ...newData}ผมคิดว่ามีการพิมพ์ผิดในตัวอย่างระดับร้านค้าของคุณในวิธีการปรับปรุงต้องเขียนบรรทัดแรกของวิธีการดังต่อไปนี้:
Norbert

2
ตอบโต้ท้อมรดกในความโปรดปรานขององค์ประกอบ reactjs.org/docs/composition-vs-inheritance.html
Fred

1
เพียงแค่สงสัยเกี่ยวกับความชัดเจน / อ่านง่ายวิธี coud this.setState (this.state) จะดีกว่า this.forceUpdate ()?
Zoman

17

ดังนั้นฉันคิดว่าคำถามของฉันคือ: องค์ประกอบการตอบสนองต้องมีสถานะเพื่อแสดงซ้ำหรือไม่ มีวิธีบังคับให้ส่วนประกอบอัปเดตตามต้องการโดยไม่เปลี่ยนสถานะหรือไม่

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

หากคุณต้องการบังคับให้แสดงซ้ำอีกครั้งด้วยตนเองคุณแทบจะไม่ได้ทำสิ่งที่ถูกต้อง


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

กรุณาคุณสามารถตรวจสอบคำถามนี้stackoverflow.com/questions/61277292/… ?
HuLu ViCa

4

คุณสามารถทำได้สองวิธี:

1. ใช้ forceUpdate()วิธีการ:

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

2. ส่ง this.state ไปยังsetState()เมธอด

บรรทัดของรหัสต่อไปนี้เอาชนะปัญหาด้วยตัวอย่างก่อนหน้านี้:

this.setState(this.state);

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


2
เนื่องจาก setState ได้รับแบทช์จึงน่าจะปลอดภัยกว่า:this.setState(prevState => prevState);
Mark Galloway

1
ไม่แน่ใจจริงๆว่าทำไมเป็น 'ความผิดพลาด' ชื่อของวิธีการ ('forceUpdate') ไม่สามารถชัดเจนได้: บังคับให้ทำการอัปเดตเสมอ
Zoman

4

มีสองสามวิธีในการแสดงส่วนประกอบของคุณอีกครั้ง:

ทางออกที่ง่ายที่สุดคือใช้เมธอด forceUpdate ():

this.forceUpdate()

อีกวิธีหนึ่งคือการสร้างไม่ใช้คีย์ในสถานะ (nonUsedKey) และเรียกใช้ฟังก์ชัน setState พร้อมการอัปเดต nonUsedKey นี้:

this.setState({ nonUsedKey: Date.now() } );

หรือเขียนสถานะปัจจุบันทั้งหมด:

this.setState(this.state);

การเปลี่ยนอุปกรณ์ประกอบฉากยังช่วยให้แสดงส่วนประกอบอีกด้วย


3

เพื่อความสมบูรณ์คุณยังสามารถทำสิ่งนี้ได้ในองค์ประกอบการใช้งาน:

const [, updateState] = useState();
const forceUpdate = useCallback(() => updateState({}), []);
// ...
forceUpdate();

หรือเป็นตะขอที่ใช้ซ้ำได้:

const useForceUpdate = () => {
  const [, updateState] = useState();
  return useCallback(() => updateState({}), []);
}
// const forceUpdate = useForceUpdate();

ดู: https://stackoverflow.com/a/53215514/2692307

โปรดทราบว่าการใช้กลไกการอัพเดทแบบบังคับยังคงเป็นการปฏิบัติที่ไม่ดีเนื่องจากขัดต่อความคิดตอบโต้ดังนั้นจึงควรหลีกเลี่ยงหากเป็นไปได้


2

เราสามารถใช้ this.forceUpdate () ดังต่อไปนี้

       class MyComponent extends React.Component {



      handleButtonClick = ()=>{
          this.forceUpdate();
     }


 render() {

   return (
     <div>
      {Math.random()}
        <button  onClick={this.handleButtonClick}>
        Click me
        </button>
     </div>
    )
  }
}

 ReactDOM.render(<MyComponent /> , mountNode);

ส่วน 'Math.random' องค์ประกอบใน DOM เท่านั้นจะได้รับการปรับปรุงแม้ว่าคุณจะใช้ setState เพื่อแสดงองค์ประกอบอีกครั้ง

คำตอบทั้งหมดในที่นี้คือการเสริมคำถามเพื่อความเข้าใจอย่างถูกต้อง ... เนื่องจากเรารู้ว่าจะแสดงองค์ประกอบอีกครั้งโดยไม่ใช้ setState ({}) คือการใช้ forceUpdate ()

รหัสข้างต้นทำงานกับ setState ดังนี้

 class MyComponent extends React.Component {



             handleButtonClick = ()=>{
                this.setState({ });
              }


        render() {
         return (
  <div>
    {Math.random()}
    <button  onClick={this.handleButtonClick}>
      Click me
    </button>
  </div>
)
  }
 }

ReactDOM.render(<MyComponent /> , mountNode);

1

เพียงตอบกลับอีกครั้งเพื่อสำรองคำตอบที่ยอมรับ :-)

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

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

เครื่องมือเช่น MobX ที่ใช้วิธีการ OO กำลังทำสิ่งนี้ใต้พื้นผิว (จริง ๆ แล้ว MobX โทรrender()โดยตรง)


0

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

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

class Example extends Component{
   constructor(props){
      this.state = {temp:0};

      this.forceChange = this.forceChange.bind(this);
   }

   forceChange(){
      this.setState(prevState => ({
          temp: prevState.temp++
      })); 
   }

   render(){
      return(
         <div>{this.state.temp &&
             <div>
                  ... add code here ...
             </div>}
         </div>
      )
   }
}

เรียก this.forceChange () เมื่อคุณต้องการบังคับให้แสดงผลซ้ำ


0

ES6 - ฉันรวมตัวอย่างซึ่งเป็นประโยชน์สำหรับฉัน:

ใน "short if statement" คุณสามารถผ่านฟังก์ชันว่างดังนี้:

isReady ? ()=>{} : onClick

นี่น่าจะเป็นวิธีที่สั้นที่สุด

()=>{}



0

อีกวิธีหนึ่งคือการโทรsetState, และรักษาสถานะ:

this.setState(prevState=>({...prevState}));


0

forceUpdate () แต่ทุกครั้งที่ฉันเคยได้ยินใครบางคนพูดถึงมันก็ถูกติดตามด้วยคุณไม่ควรใช้มัน


-1

คุณสามารถใช้ forceUpdate () เพื่อตรวจสอบรายละเอียดเพิ่มเติม ( forceUpdate () )


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