React.Component เป็นคลาสพื้นฐานสำหรับการสร้างคอมโพเนนต์โดยใช้การสืบทอดใน React ก่อนที่จะมีการแนะนำฮุกในเวอร์ชัน 16.8 คอมโพเนนต์แบบคลาสเป็นวิธีเดียวในการจัดการสถานะและไลฟ์ไซเคิล ตามข้อมูลจาก React, 2024 คอมโพเนนต์แบบคลาสยังคงได้รับการสนับสนุน แม้ว่าคอมโพเนนต์แบบฟังก์ชันพร้อมฮุกจะถูกแนะนำสำหรับโปรเจกต์ใหม่
ประเด็นสำคัญ
React.Component เป็นคลาสนามธรรมที่ให้เมธอดในตัวสำหรับการทำงานกับสถานะ พร็อพ และไลฟ์ไซเคิลของคอมโพเนนต์ ในการสร้างคอมโพเนนต์แบบคลาส คุณต้องกำหนดคลาสที่ขยาย React.Component และนำเมธอด render ไปใช้งาน
React.Component ปรากฏใน React เวอร์ชันแรกสุด (2013) และยังคงเป็น วิธีหลัก ในการสร้างคอมโพเนนต์เป็นเวลาห้าปี ระบบนิเวศของ React ถูกสร้างขึ้นรอบคลาส: คอมโพเนนต์ลำดับสูง (HOC), render props, บริบท — รูปแบบทั้งหมดนี้ถูกนำไปใช้งานโดยใช้ไวยากรณ์คลาส
ด้วยการเปิดตัว React 16.8 ในปี 2019 ทีม React ได้แนะนำ ฮุก เป็นทางเลือกแทนคลาส ฮุกแก้ปัญหาเดียวกัน — สถานะ เอฟเฟกต์ บริบท — แต่ไม่ต้องใช้การสืบทอดและการผูกบริบทที่ซับซ้อน React.Component ยังคงได้รับการสนับสนุนอย่างเต็มที่ แต่วิธีการแบบฟังก์ชันถูกแนะนำสำหรับโปรเจกต์ใหม่
คอมโพเนนต์แบบคลาสขั้นต่ำคือคลาสที่มีเมธอด render เพียงตัวเดียวที่ส่งคืน React-element render เป็นเมธอดบังคับเพียงตัวเดียว มันต้องเป็นฟังก์ชันบริสุทธิ์ของ this.props และ this.state: ชุดพร็อพและสถานะเดียวกันให้ผลลัพธ์เดียวกัน
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
คอนสตรัคเตอร์ทำงานก่อนการเมานต์ มันเรียก super(props) เพื่อส่งพร็อพไปยังคลาสแม่และเริ่มต้น this.state การใช้คอนสตรัคเตอร์เพื่อวัตถุประสงค์อื่น — การสมัครสมาชิก, การเรียก API — ไม่แนะนำ; componentDidMount มีไว้สำหรับสิ่งนั้น
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <p>Count: {this.state.count}</p>;
}
}
this.state เป็นออบเจกต์ที่เก็บข้อมูลของคอมโพเนนต์ การเปลี่ยนแปลงโดยตรง (this.state.count = 1) ถูกห้าม — มันไม่ก่อให้เกิดการเรนเดอร์ใหม่และทำลายการคาดเดาได้ ต้องอัปเดตสถานะผ่าน this.setState ซึ่งสร้างออบเจกต์สถานะใหม่และก่อให้เกิดการเรนเดอร์ใหม่
setState สามารถรับออบเจกต์หรือฟังก์ชัน รูปแบบฟังก์ชันถูกเลือกเมื่อสถานะใหม่ขึ้นอยู่กับสถานะก่อนหน้า: this.setState(prev => ({ count: prev.count + 1 })) React สามารถรวมคำเรียก setState หลายครั้งเป็นชุดเดียวเพื่อเพิ่มประสิทธิภาพ
class Toggle extends Component {
constructor(props) {
super(props);
this.state = { isOn: false };
}
handleClick() {
this.setState(prev => ({ isOn: !prev.isOn }));
}
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
คุณสมบัติที่สำคัญของ setState คือมันเป็น อะซิงโครนัส หลังจากเรียก setState สถานะจะไม่อัปเดตทันที หากคุณต้องการดำเนินการหลังจากการอัปเดต ให้ส่งคอลแบ็กเป็นอาร์กิวเมนต์ที่สอง: this.setState(newState, () => console.log(this.state))
คอมโพเนนต์แบบคลาสมีเมธอดที่กำหนดไว้ล่วงหน้าที่ React เรียกในช่วงเวลาที่กำหนด การเมานต์ — constructor → render → componentDidMount การอัปเดต — render → componentDidUpdate การเลิกเมานต์ — componentWillUnmount
| เมธอด | ระยะ | วัตถุประสงค์ |
|---|---|---|
| constructor | การเมานต์ | เริ่มต้นสถานะและผูกเมธอด |
| render | ทุกครั้ง | ส่งคืน React-element (บังคับ) |
| componentDidMount | หลังเมานต์ | คำขอ API, การสมัครสมาชิก, ตัวจับเวลา |
| componentDidUpdate | หลังอัปเดต | ตอบสนองต่อการเปลี่ยนแปลงพร็อพ/สถานะ |
| componentWillUnmount | ก่อนลบ | ทำความสะอาดการสมัครสมาชิก ตัวจับเวลา ตัวฟังเหตุการณ์ |
componentDidMount เป็นสถานที่หลักสำหรับ เอฟเฟกต์ข้างเคียง หลังจากการเรนเดอร์ครั้งแรก ที่นี่คุณดำเนินการคำขอ HTTP, สร้างการเชื่อมต่อ WebSocket และเริ่มตัวจับเวลา หากคุณไม่ทำความสะอาดการสมัครสมาชิกใน componentWillUnmount จะเกิดการรั่วไหลของหน่วยความจำ
class UserProfile extends Component {
componentDidMount() {
fetch(`/api/users/${this.props.userId}`)
.then(res => res.json())
.then(data => this.setState({ user: data }));
}
componentWillUnmount() {
// Cancel request on unmount
}
render() {
return <div>{this.state.user?.name}</div>;
}
}
ใน JavaScript เมธอดของคลาสไม่ได้ผูกกับอินสแตนซ์โดยค่าเริ่มต้น หากคุณส่งเมธอดเป็นคอลแบ็ก — ไปยังตัวจัดการเหตุการณ์, ไปยังตัวจับเวลา — this จะเป็น undefined (ในโหมดเข้มงวด) หรือ window (ไม่มีโหมดเข้มงวด) หากไม่ผูก this.setState จะโยนข้อผิดพลาด
มีสามวิธีในการผูก: bind ในคอนสตรัคเตอร์, arrow function ในคอลแบ็ก และ class field กับ arrow function วิธีแรกเป็นคำแนะนำอย่างเป็นทางการของ React: ผูกครั้งเดียวในคอนสตรัคเตอร์ โดยไม่สร้างฟังก์ชันใหม่ทุกครั้งที่เรนเดอร์
// Method 1: bind in constructor (recommended)
class MyComponent extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}
Class fields — ไวยากรณ์สมัยใหม่พร้อมการผูกอัตโนมัติ Arrow function ในคุณสมบัติของคลาสจะจับ this จากขอบเขตของคอนสตรัคเตอร์ ข้อเสียคือเมธอดถูกสร้างขึ้นในแต่ละอินสแตนซ์ ไม่ใช่บนต้นแบบ ซึ่งเพิ่มการใช้หน่วยความจำสำหรับคอมโพเนนต์หลายร้อยตัวชนิดเดียวกัน
การเลือกระหว่างคลาสและฟังก์ชันไม่ใช่แค่เรื่องของไวยากรณ์ คอมโพเนนต์แบบฟังก์ชัน พร้อมฮุกแก้ปัญหาที่มีอยู่ในคลาส: การทำซ้ำตรรกะในเมธอดไลฟ์ไซเคิลที่แตกต่างกัน (componentDidMount + componentDidUpdate), ความซับซ้อนกับ this และไม่สามารถแยกตรรกะที่เกี่ยวข้องออกเป็นบล็อกที่นำกลับมาใช้ใหม่ได้
คอมโพเนนต์แบบฟังก์ชัน ทดสอบง่ายกว่า — ไม่มีสถานะภายใน (ซึ่งก่อนฮุกมีเฉพาะในคลาส) และไม่ต้องการการเมานต์ใน DOM เพื่อตรวจสอบคอลแบ็ก React แนะนำคอมโพเนนต์แบบฟังก์ชันสำหรับโปรเจกต์ใหม่ทั้งหมด; เอกสารและตัวอย่างถูกเขียนด้วยคอมโพเนนต์เหล่านี้
คอมโพเนนต์แบบคลาสยังคงเป็นตัวเลือกที่ดีที่สุดเมื่อทำงานกับ โค้ดเก่า หากโปรเจกต์เริ่มก่อนปี 2019 โปรเจกต์นั้นอาจมีคอมโพเนนต์แบบคลาสนับพัน การเขียนใหม่ทั้งหมดเป็นฮุกในสปรินต์เดียวมีความเสี่ยง React รับประกันความเข้ากันได้ย้อนหลัง: คอมโพเนนต์แบบคลาสจะไม่ถูกลบ
การย้ายทีละน้อยเริ่มต้นด้วยการวิเคราะห์คอมโพเนนต์ คอมโพเนนต์ง่าย ๆ ที่ไม่มีสถานะ ถูกแปลงก่อน — มันถูกแทนที่ด้วยฟังก์ชันได้อย่างง่ายดาย จากนั้น — คอมโพเนนต์ที่มีฟิลด์สถานะหนึ่งหรือสองฟิลด์ ซึ่ง useState แทนที่ this.state และ this.setState โดยตรง
คอมโพเนนต์ที่ซับซ้อนที่มีหลายเมธอดไลฟ์ไซเคิลถูกแปลงผ่าน useEffect ตรรกะจาก componentDidMount + componentDidUpdate ถูกแบ่งออกเป็นคำเรียก useEffect แยกต่างหากพร้อมการพึ่งพาที่แตกต่างกัน componentWillUnmount ถูกแทนที่ด้วยฟังก์ชันส่งคืนภายใน useEffect สำหรับตรรกะสถานะที่ซับซ้อน ให้ใช้ useReducer
เครื่องมือการย้ายอัตโนมัติ — @phenomnomnominal/ts-react-class-to-hook หรือสคริปต์ codemod — สามารถแปลงคลาสอย่างง่ายได้โดยอัตโนมัติ สำหรับกรณีที่ซับซ้อน การย้ายยังคงเป็นงานที่ต้องทำด้วยตนเองซึ่งต้องเข้าใจตรรกะของคอมโพเนนต์ต้นทาง
คำถามที่พบบ่อย
ใช่ super(props) ส่งพร็อพไปยัง React.Component แม่ หากไม่มีการเรียกนี้ this.props จะเป็น undefined ภายในคอนสตรัคเตอร์ ใน render และเมธอดไลฟ์ไซเคิล พร็อพสามารถใช้ได้แม้ไม่มี super แต่เป็นพฤติกรรมพลอยได้ของการนำไปใช้งาน
React รวมคำเรียก setState หลายครั้งเป็นชุดเดียวเพื่อลดการเรนเดอร์ใหม่ที่ไม่จำเป็น หาก setState เป็นซิงโครนัส แต่ละคำเรียกจะก่อให้เกิดการเรนเดอร์ทันที ทำให้ประสิทธิภาพลดลงระหว่างการอัปเดตจำนวนมาก
ไม่ได้ ฮุก ทำงานเฉพาะในคอมโพเนนต์แบบฟังก์ชัน สำหรับโปรเจกต์ที่มีคอมโพเนนต์แบบคลาส รูปแบบเก่าทั้งหมดยังคงใช้ได้: render props, HOC และ Consumer สำหรับบริบท การย้ายไปยังฮุกต้องแปลงคลาสเป็นฟังก์ชัน
React.PureComponent นำ shouldComponentUpdate ไปใช้ด้วยการเปรียบเทียบพร็อพและสถานะแบบผิวเผิน ต่างจาก Component ที่เรนเดอร์ใหม่เสมอเมื่อ setState PureComponent ข้ามการเรนเดอร์ใหม่หากข้อมูลไม่เปลี่ยนแปลง นี่เป็นการเพิ่มประสิทธิภาพสำหรับคอมโพเนนต์ที่ไม่มีการซ้อนซับซ้อน
ใช้ componentDidCatch และ getDerivedStateFromError componentDidCatch(error, info) บันทึกข้อผิดพลาด getDerivedStateFromError อัปเดตสถานะเพื่อแสดง UI สำรอง เมธอดเหล่านี้ทำงานเฉพาะในคอมโพเนนต์แบบคลาส — ฟังก์ชันต้องมีคอมโพเนนต์ ErrorBoundary ที่ครอบอยู่
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ