การเริ่มต้นสนามควบคุมหลังการก่อสร้าง

ฉันกำลังพยายามเริ่มต้นฟิลด์ควบคุมในการตอบสนอง แต่ฉันไม่ทราบค่าเริ่มต้นระหว่างการก่อสร้าง

ความเข้าใจของฉันคือแม้ว่าคุณจะทำ setState ซึ่งทำให้เกิดการเรนเดอร์ซ้ำ สิ่งนี้จะไม่เปลี่ยนค่าของการควบคุม - ฉันไม่แน่ใจว่าทำไม

ดังนั้นสิ่งต่อไปนี้จะไม่ทำงาน:

componentDidMount() {

   ...   // code to get value

   this.setState({ value: "hello world" });
   return ( <input type="text" value={this.state.value} onChange={this.handleChange} />
}

ฉันพยายามแสดงผลอินพุตในการเรียกกลับ setState แทนเพื่อให้แน่ใจว่าได้ตั้งค่าไว้แล้ว:

componentDidMount() {

   ...   // code to get value

   this.setState({ value: "hello world" }, this.renderInput);
}

renderInput = () => {
   this.input = ( <input type="text" value={this.state.value} onChange={this.handleChange} />
}

หมายเหตุ: แบบฟอร์มของฉันมี {this.input)

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

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


person Ben    schedule 12.04.2018    source แหล่งที่มา
comment
เหตุใดคุณจึงส่งคืน <input> จาก componentDidMount() this.handleChangeของคุณกำลังทำอะไรอยู่? คุณสามารถรวมฟังก์ชัน render() ของคุณได้ไหม   -  person Pipe    schedule 12.04.2018
comment
เห็นด้วย ฉันไม่คิดว่าการส่งคืนองค์ประกอบจาก componentDidMount จะทำอะไรไม่ได้เลย   -  person ecraig12345    schedule 13.04.2018
comment
นอกจากนี้ เราต้องดู handleChange อย่างแน่นอน เนื่องจากนั่นอาจเป็นสาเหตุของปัญหา   -  person ecraig12345    schedule 13.04.2018


คำตอบ (1)


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


(คำตอบเดิม)

วิธีแก้ปัญหาที่ง่ายที่สุดคืออย่าเรนเดอร์ <input> จนกว่าคุณจะทราบค่าเริ่มต้น ใช้สิ่งนี้ในตำแหน่งที่เหมาะสมใน render():

{ typeof this.state.value === 'string' ?
  <input type="text" value={this.state.value} onChange={this.handleChange} /> :
  null }

ข้อเสียเปรียบของแนวทางนี้: หากมีองค์ประกอบอื่นในแบบฟอร์ม พวกเขาจะ "กระโดด" เมื่อฟิลด์นี้ปรากฏขึ้น ซึ่งไม่ดีนัก

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

componentDidMount() {
  getInitialValue().then((initialValue) => {
    this.setState({ value: initialValue, isLoading: false });
  });
}

render() {
  if (this.state.isLoading)
    return null; // or something like <div>Loading...</div>

  // else, return normal stuff
}
person ecraig12345    schedule 13.04.2018