มีสามคำตอบที่นี่ขึ้นอยู่กับเวอร์ชันของ React ที่คุณ (บังคับให้) ทำงาน (ไอเอ็นจี) ด้วยและไม่ว่าคุณต้องการใช้ hooks หรือไม่
สิ่งแรกก่อน:
สิ่งสำคัญคือต้องเข้าใจวิธีการทำงานของ React เพื่อให้คุณสามารถทำสิ่งต่าง ๆ ได้อย่างถูกต้อง (protip: มันยอดเยี่ยมมากที่จะทำแบบฝึกหัดการสอน React บนเว็บไซต์ React มันเขียนได้ดีและครอบคลุมพื้นฐานทั้งหมดในแบบที่อธิบายวิธีการทำจริง สิ่ง) "ถูกต้อง" ที่นี่หมายความว่าคุณกำลังเขียนส่วนต่อประสานแอปพลิเคชันที่จะแสดงผลในเบราว์เซอร์ อินเทอร์เฟซทั้งหมดเกิดขึ้นใน React ไม่ใช่ใน "สิ่งที่คุณคุ้นเคยหากคุณกำลังเขียนเว็บเพจ" (นี่คือสาเหตุที่แอป React เป็น "แอพ" ไม่ใช่ "หน้าเว็บ")
แอปพลิเคชันที่ทำปฏิกิริยาถูกเรนเดอร์จากสองสิ่ง:
- คุณสมบัติของส่วนประกอบตามที่ประกาศโดยผู้ปกครองใดก็ตามที่สร้างอินสแตนซ์ขององค์ประกอบนั้นซึ่งผู้ปกครองสามารถปรับเปลี่ยนตลอดวงจรชีวิตของมันและ
- สถานะภายในของส่วนประกอบซึ่งสามารถแก้ไขได้ตลอดวงจรชีวิตของมันเอง
สิ่งที่คุณไม่ได้ทำอย่างชัดเจนเมื่อคุณใช้ React คือการสร้างองค์ประกอบ HTML แล้วใช้สิ่งนั้นเมื่อคุณบอก React ให้ใช้<input>
ตัวอย่างเช่นคุณไม่ได้สร้างองค์ประกอบอินพุต HTML คุณจะบอก React เพื่อสร้างวัตถุอินพุต React ที่เกิดขึ้นกับการแสดงผลเป็นองค์ประกอบเข้า HTML และมีการจัดการรูปลักษณ์ที่เหตุการณ์แต่ไม่ได้ถูกควบคุมโดยเหตุการณ์การป้อนข้อมูลองค์ประกอบ HTML ของ
เมื่อใช้ React สิ่งที่คุณกำลังทำคือการสร้างองค์ประกอบ UI ของแอปพลิเคชันที่นำเสนอผู้ใช้ด้วยข้อมูล (มักแก้ไขได้) ด้วยการโต้ตอบกับผู้ใช้ที่เปลี่ยนสถานะของคอมโพเนนต์ซึ่งอาจทำให้ส่วนของอินเทอร์เฟซแอพพลิเคชันของคุณแสดงสถานะใหม่ ในโมเดลนี้สถานะจะเป็นสิทธิ์ขั้นสุดท้ายเสมอไม่ใช่ "ไลบรารี UI ใด ๆ ก็ตามที่ใช้แสดงผล" ซึ่งบนเว็บคือ DOM ของเบราว์เซอร์ DOM เป็นสิ่งที่เกือบจะเกิดขึ้นภายหลังในรูปแบบการเขียนโปรแกรมนี้: มันเป็นเพียงเฟรมเวิร์ก UI เฉพาะที่ React เกิดขึ้นที่จะใช้
ดังนั้นในกรณีขององค์ประกอบอินพุตตรรกะคือ:
- คุณพิมพ์ในองค์ประกอบอินพุต
- ไม่มีอะไรเกิดขึ้นกับองค์ประกอบการป้อนข้อมูลของคุณ แต่เหตุการณ์ได้ขัดขวางโดยตอบสนองและฆ่าทิ้งทันที ,
- ตอบกลับเหตุการณ์ต่อไปยังฟังก์ชันที่คุณตั้งค่าไว้สำหรับการจัดการเหตุการณ์
- ฟังก์ชั่นนั้นอาจกำหนดการอัพเดทสถานะ
- ถ้าเป็นเช่นนั้น React จะรันการอัพเดทสถานะนั้น (แบบอะซิงโครนัส!) และจะทริกเกอร์การ
render
โทรหลังจากการอัพเดท แต่เฉพาะในกรณีที่การอัพเดทสถานะเปลี่ยนสถานะ
- เพียง แต่หลังจากนี้จะแสดงผลได้ที่สถานที่จะแสดง UI ที่คุณ "พิมพ์ตัวอักษร"
ทั้งหมดนี้เกิดขึ้นในเวลาไม่กี่มิลลิวินาทีหากไม่น้อยดังนั้นดูเหมือนว่าคุณพิมพ์ลงในองค์ประกอบการป้อนข้อมูลในลักษณะเดียวกับที่คุณคุ้นเคยจาก "เพียงแค่ใช้องค์ประกอบการป้อนข้อมูลบนหน้าเว็บ" แต่นั่นไม่ใช่สิ่งที่แน่นอน ที่เกิดขึ้น
ดังนั้นด้วยวิธีที่กล่าวถึงวิธีรับค่าจากองค์ประกอบใน React:
ทำปฏิกิริยา 15 และต่ำกว่าด้วย ES5
ในการทำสิ่งต่าง ๆ อย่างถูกต้องส่วนประกอบของคุณมีค่าสถานะซึ่งจะแสดงผ่านฟิลด์อินพุตและเราสามารถอัปเดตได้โดยทำให้องค์ประกอบ UI นั้นส่งกิจกรรมการเปลี่ยนแปลงกลับไปที่องค์ประกอบ:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
ดังนั้นเราจึงบอก React ให้ใช้updateInputValue
ฟังก์ชั่นเพื่อจัดการกับการโต้ตอบของผู้ใช้ใช้setState
ในการกำหนดตารางการอัพเดทสถานะและข้อเท็จจริงที่ว่าการrender
แตะลงthis.state.inputValue
นั้นหมายความว่าเมื่อมันแสดงผลหลังจากอัพเดทสถานะผู้ใช้จะเห็นข้อความอัปเดตตามสิ่งที่พิมพ์
ภาคผนวกตามความคิดเห็น
ระบุว่าอินพุท UI แสดงค่าสถานะ (พิจารณาว่าจะเกิดอะไรขึ้นหากผู้ใช้ปิดแท็บกึ่งกลางและแท็บจะได้รับการคืนค่าทั้งหมดที่พวกเขากรอกจะถูกกู้คืนหรือไม่ถ้าใช่นั่นคือสถานะ) นั่นอาจทำให้คุณรู้สึกว่ารูปแบบขนาดใหญ่ต้องการแบบฟอร์มป้อนข้อมูลหลายสิบหรือหลายร้อยแบบ แต่การตอบสนองนั้นเกี่ยวกับการสร้างแบบจำลอง UI ของคุณในแบบที่รักษาได้: คุณไม่มีช่องป้อนข้อมูลอิสระ 100 ช่องคุณมีกลุ่มของอินพุตที่เกี่ยวข้อง กลุ่มในองค์ประกอบและสร้างฟอร์ม "ต้นแบบ" ของคุณเป็นกลุ่มของกลุ่ม
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
นอกจากนี้ยังง่ายต่อการบำรุงรักษามากกว่าองค์ประกอบแบบฟอร์มเดี่ยวขนาดยักษ์ แบ่งกลุ่มออกเป็นส่วนประกอบด้วยการบำรุงรักษาสถานะโดยที่แต่ละส่วนประกอบมีหน้าที่รับผิดชอบในการติดตามฟิลด์อินพุตสองสามครั้ง
คุณอาจรู้สึกว่าเป็น "ความยุ่งยาก" ในการเขียนรหัสทั้งหมด แต่นั่นเป็นการประหยัดที่ผิดพลาด: นักพัฒนาซอฟต์แวร์ที่ไม่ได้เป็นคุณรวมถึงอนาคตที่คุณจะได้รับประโยชน์อย่างมากจากการเห็นอินพุตทั้งหมดติดอยู่อย่างชัดเจนเพราะ ทำให้เส้นทางรหัสง่ายต่อการติดตาม อย่างไรก็ตามคุณสามารถเพิ่มประสิทธิภาพได้ตลอดเวลา ตัวอย่างเช่นคุณสามารถเขียนตัวเชื่อมโยงสถานะ
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});
แน่นอนว่ามีรุ่นที่ได้รับการปรับปรุงให้ดีขึ้นดังนั้นให้https://npmjs.comและค้นหาโซลูชันการเชื่อมโยงสถานะ React ที่คุณชอบมากที่สุด โอเพ่นซอร์สส่วนใหญ่เกี่ยวกับการค้นหาสิ่งที่คนอื่นทำไปแล้วและการใช้สิ่งนั้นแทนที่จะเขียนทุกอย่างด้วยตัวเอง
ทำปฏิกิริยา 16 (และการเปลี่ยนผ่าน 15.5) และ JS 'ทันสมัย'
ตั้งแต่ React 16 (และเริ่มด้วย soft 15.5) การcreateClass
โทรไม่ได้รับการสนับสนุนอีกต่อไปและจำเป็นต้องใช้ไวยากรณ์คลาส นี้จะเปลี่ยนสิ่งที่สอง: ไวยากรณ์ระดับที่เห็นได้ชัด แต่ยังthis
บริบทผูกพันที่createClass
จะทำ "ฟรี" เพื่อที่จะให้แน่ใจว่าสิ่งที่ยังคงทำงานให้แน่ใจว่าคุณกำลังใช้ "ลูกศรไขมัน" สัญกรณ์สำหรับthis
บริบทการรักษาฟังก์ชั่นที่ไม่ระบุชื่อในการonWhatever
ขนย้ายวัสดุเช่นonChange
ใช้เราในรหัสที่นี่:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
};
}
render() {
return (
//...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
//...
);
},
updateInputValue(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
คุณอาจเคยเห็นคนใช้ตัวbind
สร้างของพวกเขาสำหรับฟังก์ชั่นจัดการเหตุการณ์ทั้งหมดเช่นนี้
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
อย่าทำอย่างนั้น
เกือบทุกครั้งที่คุณใช้bind
สุภาษิต "คุณทำผิด" ใช้ คลาสของคุณได้กำหนดต้นแบบของวัตถุแล้วและได้กำหนดบริบทของอินสแตนซ์แล้ว อย่าเอาbind
สิ่งที่ดีไปกว่านั้น ใช้การส่งต่อเหตุการณ์ปกติแทนการทำซ้ำการเรียกใช้ฟังก์ชันทั้งหมดของคุณในตัวสร้างเนื่องจากการทำซ้ำนั้นจะเพิ่มพื้นผิวบั๊กของคุณและทำให้การติดตามข้อผิดพลาดนั้นยากขึ้นเพราะปัญหาอาจอยู่ในตัวสร้างของคุณแทนที่จะเป็นที่ที่คุณเรียกรหัสของคุณ รวมถึงการวางภาระการบำรุงรักษาให้กับผู้อื่นที่คุณ (มีหรือเลือก) เพื่อทำงานกับ
ใช่ฉันรู้ว่าเอกสารตอบกลับบอกว่าไม่เป็นไร ไม่ทำไม่ได้
ทำปฏิกิริยา 16.8 โดยใช้ฟังก์ชั่นส่วนประกอบพร้อม hooks
ในฐานะของ React 16.8 ส่วนประกอบฟังก์ชั่น (เช่นตัวอักษรเพียงฟังก์ชั่นที่ใช้เวลาบางส่วนprops
เป็นอาร์กิวเมนต์สามารถนำมาใช้เป็นถ้าเป็นตัวอย่างของชั้นองค์ประกอบโดยไม่เคยเขียนชั้นเรียน) นอกจากนี้ยังจะได้รับของรัฐผ่านการใช้ตะขอ
หากคุณไม่ต้องการรหัสคลาสเต็มและฟังก์ชั่นอินสแตนซ์เดียวจะทำเช่นนั้นตอนนี้คุณสามารถใช้useState
hook เพื่อทำให้ตัวเองเป็นตัวแปรสถานะเดียวและฟังก์ชั่นอัพเดทซึ่งทำงานเหมือนกับตัวอย่างข้างต้นโดยประมาณsetState
เรียกฟังก์ชัน:
import { useState } from 'react';
function myFunctionalComponentFunction() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<div>
<label>Please specify:</label>
<input value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}
ก่อนหน้านี้ความแตกต่างอย่างไม่เป็นทางการระหว่างคลาสและส่วนประกอบของฟังก์ชั่นคือ "องค์ประกอบของฟังก์ชั่นไม่มีสถานะ" ดังนั้นเราจึงไม่สามารถซ่อนอยู่ข้างหลังนั้นอีกต่อไป: ความแตกต่างระหว่างองค์ประกอบของฟังก์ชั่นและส่วนประกอบของชั้นเรียนเอกสารตอบโต้ที่เขียนด้วยลายมือ(ไม่มีคำอธิบายทางลัดหนึ่งซับเพื่อแปลความหมายให้คุณเข้าใจผิด!) ซึ่งคุณควรอ่านเพื่อให้คุณรู้ว่าคุณกำลังทำอะไรอยู่และสามารถรู้ได้ว่าคุณเลือกโซลูชันที่ดีที่สุด (อะไรก็ตามที่มีความหมายสำหรับคุณ) จากปัญหาที่คุณมี
this.onSubmit.bind(this);