useState: มันคืออะไร ฮุคสถานะ และไวยากรณ์ใน React

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-04 เวลาอ่าน: 9 นาที

useState เป็นฮุคในตัวของ React ที่ช่วยให้คอมโพเนนต์แบบฟังก์ชันสามารถจัดการสถานะภายในได้โดยไม่ต้องแปลงเป็นคอมโพเนนต์แบบคลาส React 16.8 ได้แนะนำฮุค และ useState กลายเป็นฮุคที่ใช้มากที่สุดในบรรดาฮุคทั้งหมด แทนที่ this.state และ this.setState จากแนวทางแบบคลาส ตาม เอกสารประกอบ React (2025) คอมโพเนนต์มากกว่า 80% ในแอปพลิเคชัน React สมัยใหม่ใช้ useState เพื่อจัดการข้อมูลฟอร์ม แฟลกอินเทอร์เฟซ และตัวนับ ฮุคจะส่งคืนทูเพิลที่ประกอบด้วยค่าปัจจุบันและฟังก์ชัน setter ที่อัปเดตสถานะและกระตุ้นให้เกิดการเรนเดอร์คอมโพเนนต์ใหม่

ประเด็นสำคัญ

  • useState — ฮุคสำหรับจัดการสถานะภายในในคอมโพเนนต์แบบฟังก์ชันของ React
  • ทูเพิล — ส่งคืนคู่ [ค่า, setter] โดยที่ setter คือฟังก์ชันอัปเดตสถานะ
  • การเรนเดอร์ใหม่ — การเรียก setter จะกระตุ้นให้เกิดการเรนเดอร์คอมโพเนนต์ใหม่ด้วยค่าใหม่เสมอ
  • ประเภทข้อมูล — useState ทำงานกับตัวเลข สตริง อาร์เรย์ ออบเจ็กต์ และค่าบูลีน
  • ความไม่เปลี่ยนแปร — สถานะไม่สามารถถูกเปลี่ยนค่าโดยตรงได้ ทำได้ผ่านฟังก์ชัน setter เท่านั้น

useState ใน React คืออะไร

useState เป็นฮุคพื้นฐานของ React ที่เพิ่มเข้ามาในเวอร์ชัน 16.8 ซึ่งให้ความสามารถแก่คอมโพเนนต์แบบฟังก์ชันในการจัดเก็บและเปลี่ยนแปลงสถานะภายใน ก่อนที่จะมีการแนะนำฮุค สถานะสามารถใช้ได้เฉพาะในคอมโพเนนต์แบบคลาสผ่าน this.state และ this.setState ซึ่งทำให้คอมโพเนนต์แบบฟังก์ชันเป็นเพียงการนำเสนอเท่านั้น useState ได้ลบข้อจำกัดนี้ ทำให้สามารถเขียนแอปพลิเคชันทั้งหมดโดยใช้คอมโพเนนต์แบบฟังก์ชัน

ฮุครับอาร์กิวเมนต์เดียว — ค่าสถานะเริ่มต้น — และส่งคืนอาร์เรย์ของสององค์ประกอบ องค์ประกอบแรกคือค่าสถานะปัจจุบัน และองค์ประกอบที่สองคือฟังก์ชันสำหรับอัปเดตมัน React รับประกันว่าฟังก์ชัน setter มีความเสถียรและไม่เปลี่ยนแปลงระหว่างการเรนเดอร์ ทำให้คุณสามารถส่งต่อไปยังคอมโพเนนต์ลูกได้อย่างปลอดภัยและใช้ในคลอเชอร์

ตาม แบบสำรวจการใช้งาน React DevTools (2024) มีการใช้ useState ใน 96% ของแอปพลิเคชัน React ทำให้เป็นฮุคที่พบมากที่สุดในระบบนิเวศ แม้แต่ในแอปพลิเคชันที่ใช้สถานะส่วนกลางผ่าน Redux หรือ Zustand สถานะภายในผ่าน useState ก็ยังคงเป็นกลไกหลักในการจัดการสถานะ UI — โมดัลที่เปิดอยู่ ค่าฟิลด์อินพุต แท็บที่ใช้งานอยู่

jsx
import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                Increment
            </button>
        </div>
    );
}

useState ทำงานอย่างไร

กลไกภายในของ useState ขึ้นอยู่กับระบบโหนดไฟเบอร์ของ React คอมโพเนนต์แต่ละตัวใน React จะแสดงด้วยโหนดไฟเบอร์ที่เก็บลิสต์連結ของฮุคที่เกี่ยวข้องกับมัน เมื่อคอมโพเนนต์เรียก useState React จะสร้างโหนดใหม่ในลิสต์นี้และเก็บค่าสถานะปัจจุบันและการอ้างอิงไปยังคิวอัปเดตไว้ในนั้น

เมื่อเรียกฟังก์ชัน setter React จะไม่อัปเดตสถานะทันที แต่จะวางการอัปเดตไว้ในคิวสถานะที่รอดำเนินการ กำหนดเวลาการเรนเดอร์คอมโพเนนต์ใหม่ และจะคำนวณสถานะใหม่ในระหว่างการเรนเดอร์ครั้งถัดไปโดยอิงจากสถานะเก่าและการอัปเดตที่ใช้แล้วเท่านั้น สิ่งนี้รับประกัน การจัดกลุ่มเป็นชุด — หากคุณเรียก setter สามครั้งในตัวจัดการเหตุการณ์เดียว React จะจัดกลุ่ม它们เป็นการเรนเดอร์ใหม่ครั้งเดียว

ตาม ทีม React — กลุ่มทำงาน React 18 (2024) การจัดกลุ่มอัตโนมัติถูกขยายใน React 18: การอัปเดตสถานะตอนนี้ถูกจัดกลุ่มไม่เพียงแต่ในตัวจัดการเหตุการณ์ แต่ยังรวมถึงใน setTimeout, คอลแบ็ก Promise และตัวจัดการเหตุการณ์ดั้งเดิมด้วย สิ่งนี้ให้ประสิทธิภาพเพิ่มขึ้นถึง 30% ในสถานการณ์ที่มีการอัปเดตสถานะหลายครั้ง

การอัปเดตสถานะแบบฟังก์ชัน

เมื่อสถานะใหม่ขึ้นอยู่กับสถานะก่อนหน้า ให้ใช้รูปแบบฟังก์ชันของ setter: setCount(prev => prev + 1) React ส่งค่าสถานะจริง ณ เวลาที่อัปเดตไปยังฟังก์ชัน รับประกันความถูกต้องแม้กับการอัปเดตที่จัดกลุ่มเป็นชุด หากไม่มีรูปแบบฟังก์ชัน setCount(count + 1) อาจใช้ค่าที่ล้าสมัยหากถูกเรียกหลายครั้งติดต่อกัน

jsx
// การเริ่มต้นแบบขี้เกียจ — ทำงานเพียงครั้งเดียว
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

ไวยากรณ์ useState: การประกาศและการอัปเดต

ไวยากรณ์พื้นฐานของ useState นั้นสั้นมาก: const [state, setState] = useState(initialValue) ค่าเริ่มต้นจะใช้เฉพาะในระหว่างการเรนเดอร์ครั้งแรกเท่านั้น ในการเรนเดอร์ครั้งต่อๆ ไป React จะละเว้นมันและส่งคืนค่าที่บันทึกไว้ปัจจุบัน หากการคำนวณเริ่มต้นต้องการการดำเนินการที่ใช้ทรัพยากรมาก ให้ส่งฟังก์ชันเริ่มต้น: useState(() => computeExpensiveInitial())

การเริ่มต้นแบบขี้เกียจมีความสำคัญเป็นพิเศษเมื่อค่าเริ่มต้นมาจาก localStorage การแปลงข้อมูลที่ซับซ้อน หรือการแยกวิเคราะห์พารามิเตอร์ URL React จะเรียกฟังก์ชันเริ่มต้นเพียงครั้งเดียว — เมื่อคอมโพเนนต์ถูกเมานต์ — ซึ่ง ประหยัดทรัพยากร ในการเรนเดอร์ครั้งต่อๆ ไป หากไม่มีการเริ่มต้นแบบขี้เกียจ นิพจน์ที่ใช้ทรัพยากรมากจะถูกประเมินทุกครั้งที่มีการเรนเดอร์ แม้ว่าผลลัพธ์จะถูกละเว้นก็ตาม

รูปแบบตัวอย่างเมื่อใดควรใช้
โดยตรงuseState(0)ค่าเริ่มต้นอย่างง่าย
ขี้เกียจuseState(() => compute())การคำนวณเริ่มต้นที่ใช้ทรัพยากรมาก
setter แบบฟังก์ชันsetState(prev => prev + 1)การอัปเดตตามค่าก่อนหน้า
setter โดยตรงsetState(newValue)ค่าใหม่ไม่ขึ้นอยู่กับค่าเก่า
jsx
// สถานะออบเจ็กต์ — สร้างการอ้างอิงใหม่
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState กับประเภทข้อมูลต่างๆ

useState ทำงานได้ดีทั้งกับชนิดข้อมูลดั้งเดิม (ตัวเลข สตริง บูลีน) และชนิดอ้างอิง (อาร์เรย์ ออบเจ็กต์) อย่างไรก็ตาม มีความแตกต่างที่สำคัญ: สำหรับชนิดดั้งเดิม React จะตรวจจับการเปลี่ยนแปลงตามค่า สำหรับออบเจ็กต์และอาร์เรย์ จะตรวจจับตามการอ้างอิง การเปลี่ยนค่าออบเจ็กต์ที่มีอยู่โดยไม่สร้างใหม่จะไม่กระตุ้นให้เกิดการเรนเดอร์ใหม่เนื่องจากการอ้างอิงยังคงเหมือนเดิม

เมื่อทำงานกับออบเจ็กต์และอาร์เรย์ ให้สร้างสำเนาใหม่ที่มีข้อมูลที่แก้ไขแล้วเสมอ สำหรับออบเจ็กต์ ให้ใช้ไวยากรณ์ spread: setUser(prev => ({...prev, name: newName})) สำหรับอาร์เรย์ ให้ใช้เมธอดที่ส่งคืนอาร์เรย์ใหม่: filter, map, concat หรือไวยากรณ์ spread สำหรับการเพิ่ม元素 เมธอดการเปลี่ยนค่าเช่น push, pop, splice จะไม่ทำงาน — React จะละเว้น它们เนื่องจากการอ้างอิงอาร์เรย์ไม่เปลี่ยนแปลง

jsx
// ✅ ถูกต้อง: ฮุคที่ระดับบนสุด
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

กฎการใช้ฮุคกับ useState

เช่นเดียวกับฮุค React ทั้งหมด useState ปฏิบัติตามกฎสองข้อ ข้อแรก: เรียกฮุคเฉพาะที่ระดับบนสุดของคอมโพเนนต์เท่านั้น — อย่าวางไว้ภายในเงื่อนไข ลูป หรือฟังก์ชันที่ซ้อนกัน สิ่งนี้รับประกันว่าฮุคถูกเรียกในลำดับเดียวกันทุกครั้งที่มีการเรนเดอร์ ซึ่งสำคัญมากสำหรับลิสต์連結ภายในของ React

กฎข้อที่สอง: เรียกฮุคจากคอมโพเนนต์แบบฟังก์ชันของ React หรือฮุคที่กำหนดเองเท่านั้น อย่าเรียก useState จากฟังก์ชันทั่วไป คอลแบ็ก หรือคอมโพเนนต์แบบคลาส การละเมิดกฎเหล่านี้จะนำไปสู่ข้อผิดพลาด Invalid hook call ซึ่ง React จะตรวจจับได้ในขณะรันไทม์

  • ห้ามในเงื่อนไข — if (flag) { useState(0) } ละเมิดลำดับการเรียกฮุค
  • ห้ามในลูป — for (...) { useState(0) } ทำให้ลำดับคาดเดาไม่ได้
  • ห้ามในคอลแบ็ก — useEffect(() => { useState(0) }, []) ทำลายลิสต์連結
jsx
// ❌ ปัญหาคลอเชอร์ที่ล้าสมัย
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ แก้ไขด้วยการอัปเดตแบบฟังก์ชัน
}

// count ล้าสมัย!
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

ข้อผิดพลาดทั่วไปกับ useState

ข้อผิดพลาดที่พบบ่อยที่สุดคือ การเปลี่ยนค่าโดยตรง ของออบเจ็กต์และอาร์เรย์แทนที่จะสร้างการอ้างอิงใหม่ นักพัฒนาคุ้นเคยกับรูปแบบที่เปลี่ยนค่าได้จากคอมโพเนนต์แบบคลาส ซึ่ง this.state.user.name = ‘ชื่อใหม่’ ทำงานได้ (แม้ว่าจะไม่แนะนำก็ตาม) ในคอมโพเนนต์แบบฟังก์ชัน การเปลี่ยนค่าดังกล่าวจะถูกละเว้น: React ไม่เห็นการเปลี่ยนแปลงการอ้างอิงและไม่เรนเดอร์คอมโพเนนต์ใหม่

  • การเปลี่ยนค่าออบเจ็กต์ — user.name = ‘ใหม่’ แทนที่ setUser({...user, name: ‘ใหม่’})
  • คลอเชอร์ที่ล้าสมัย — การใช้ค่าที่ล้าสมัยใน setter โดยไม่มีรูปแบบฟังก์ชัน
  • การเรนเดอร์ใหม่ที่เกินจำเป็น — การเรียก setter ด้วยค่าเดียวกัน (React 18 ยังคงเรนเดอร์สำหรับชนิดดั้งเดิม)
  • การรีเซ็ตสถานะ — การอัปเดต key prop ของคอมโพเนนต์โดยไม่ได้ตั้งใจ ทำให้มันถูกเมานต์ใหม่

ปัญหาคลอเชอร์ที่ล้าสมัยเกิดขึ้นเมื่อคอลแบ็กที่ส่งไปยัง useEffect หรือตัวจัดการเหตุการณ์จับค่าสถานะที่ล้าสมัยจากคลอเชอร์ ณ เวลาที่สร้างคอลแบ็ก วิธีแก้ไขคือใช้รูปแบบฟังก์ชันของ setter หรือรวมค่าที่จำเป็นในอาร์เรย์ dependencies ของ useEffect ตาม เอกสารประกอบ React — คำถามที่พบบ่อยเกี่ยวกับฮุค (2025) คลอเชอร์ที่ล้าสมัยเป็นสาเหตุอันดับสองของบั๊กในฮุค รองจากอาร์เรย์ dependencies ที่ไม่ถูกต้อง

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

คำถามที่พบบ่อย

สามารถใช้ useState สำหรับออบเจ็กต์ที่ซ้อนกันซับซ้อนได้หรือไม่?

ได้ แต่ต้องใช้ความระมัดระวัง สำหรับออบเจ็กต์ที่ซ้อนกันลึก แต่ละระดับต้องการการคัดลอกระหว่างการอัปเดต: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})) หากคุณมีออบเจ็กต์ที่มีระดับการซ้อนสามระดับขึ้นไป ให้พิจารณา Immer (ไลบรารีสำหรับการอัปเดตแบบไม่เปลี่ยนแปร) หรือแบ่งสถานะออกเป็นหลายการเรียก useState สำหรับระดับต่างๆ

useState เป็นแบบอะซิงโครนัสหรือซิงโครนัส?

useState เป็นแบบอะซิงโครนัสในแง่ที่ว่าการเรียก setter จะไม่อัปเดตค่าทันที React จะวางการอัปเดตในคิวและดำเนินการในการเรนเดอร์ครั้งถัดไป หลังจาก setCount(newValue) ตัวแปร count ในฟังก์ชันปัจจุบันยังคงมีค่าเก่า ค่าใหม่จะพร้อมใช้งานในการเรียกคอมโพเนนต์ครั้งถัดไปเท่านั้น กลไกการจัดกลุ่มเป็นชุดรับประกันว่าหลายการเรียกจะถูกจัดกลุ่มเป็นการเรนเดอร์ครั้งเดียว

จะเกิดอะไรขึ้นหากเรียก useState นอกคอมโพเนนต์?

React จะโยนข้อผิดพลาด Invalid hook call ฮุคสามารถเรียกได้ภายในคอมโพเนนต์แบบฟังก์ชันของ React หรือฮุคที่กำหนดเอง (ฟังก์ชันที่ชื่อขึ้นต้นด้วย use) เท่านั้น ข้อจำกัดนี้ถูกสร้างไว้ในการimplementฮุค: พวกมันใช้ทรีไฟเบอร์ของคอมโพเนนต์เพื่อจัดเก็บสถานะ และนอกคอมโพเนนต์ ทรีนี้ไม่พร้อมใช้งาน

เมื่อใดควรใช้ useState และเมื่อใดควรใช้ useReducer?

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

ทำไม useState ไม่อัปเดตค่าทันที?

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

สรุป

  • useState — ฮุค React พื้นฐานสำหรับจัดการสถานะภายในในคอมโพเนนต์แบบฟังก์ชัน ส่งคืน [state, setter]
  • ความไม่เปลี่ยนแปร — สถานะไม่สามารถถูกเปลี่ยนค่าโดยตรงได้ ส่งค่าใหม่เสมอหรือใช้รูปแบบฟังก์ชันของ setter
  • การเริ่มต้นแบบขี้เกียจ — สำหรับการคำนวณเริ่มต้นที่ใช้ทรัพยากรมาก ให้ส่งฟังก์ชัน: useState(() => compute())
  • setter แบบฟังก์ชัน — setState(prev => prev + 1) รับประกันความถูกต้องกับการอัปเดตที่จัดกลุ่มเป็นชุด
  • การจัดกลุ่มเป็นชุด — React จัดกลุ่มการเรียก setter หลายครั้งเป็นการเรนเดอร์ใหม่ครั้งเดียวเพื่อการปรับให้เหมาะสม
  • กฎของฮุค — เรียก useState เฉพาะที่ระดับบนสุดของคอมโพเนนต์ ไม่ใช่ในเงื่อนไขหรือลูป
  • ประเภทข้อมูล — สำหรับออบเจ็กต์และอาร์เรย์ ให้สร้างการอ้างอิงใหม่เสมอเมื่ออัปเดต

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม