# 30 คำถามสัมภาษณ์ React ที่พบบ่อยที่สุด: คู่มือเตรียมตัวฉบับสมบูรณ์ > รวม 30 คำถามสัมภาษณ์ React ที่พบบ่อยที่สุดในปี 2026 พร้อมคำตอบเชิงลึกและตัวอย่างโค้ดเพื่อช่วยให้ผู้สมัครคว้าตำแหน่งนักพัฒนา React - Published: 2026-01-31 - Updated: 2026-04-21 - Author: SharpSkill - Tags: react interview, frontend interview, react questions, javascript, technical interview - Reading time: 18 min --- การสัมภาษณ์เทคนิค React จะวัดความเข้าใจในแนวคิดพื้นฐาน รูปแบบขั้นสูง และแนวปฏิบัติที่ดี คู่มือนี้รวบรวม 30 คำถามที่พบบ่อยที่สุด พร้อมคำตอบเชิงลึกและตัวอย่างโค้ดเพื่อให้การเตรียมตัวเป็นไปอย่างมีประสิทธิภาพ > **คำแนะนำในการเตรียมตัว** > > คำถามเหล่านี้ถูกจัดเรียงตามระดับความยาก การฝึกฝนพื้นฐานให้แม่นยำก่อนเข้าสู่แนวคิดขั้นสูงจะช่วยให้การเตรียมตัวมีโครงสร้างที่ชัดเจนยิ่งขึ้น ## พื้นฐานของ React ### 1. Virtual DOM คืออะไรและทำไม React ถึงใช้ Virtual DOM คือการแทนค่าของ DOM จริงในรูปแบบ JavaScript ที่มีน้ำหนักเบา React ใช้สิ่งนี้เพื่อปรับแต่งการอัปเดตอินเทอร์เฟซให้มีประสิทธิภาพ กระบวนการประกอบด้วยสามขั้นตอน ได้แก่ React สร้างสำเนาเสมือนของ DOM ก่อน จากนั้นเปรียบเทียบสำเนาดังกล่าวกับเวอร์ชันก่อนหน้าเมื่อมีการเปลี่ยนแปลง (อัลกอริทึม diffing) และสุดท้ายนำเฉพาะการเปลี่ยนแปลงที่จำเป็นไปใช้กับ DOM จริง (reconciliation) ```jsx // Simplified example of the concept // When state changes, React doesn't recreate the entire DOM function Counter() { const [count, setCount] = useState(0) // Only the span containing count will be updated in the real DOM // The rest of the component is untouched return (

Counter

{count}
) } ``` วิธีการนี้หลีกเลี่ยงการดำเนินการที่มีต้นทุนสูงบน DOM และทำให้สามารถอัปเดตอินเทอร์เฟซที่ซับซ้อนได้อย่างรวดเร็ว ### 2. คอมโพเนนต์แบบฟังก์ชันกับแบบคลาสต่างกันอย่างไร คอมโพเนนต์แบบฟังก์ชันคือฟังก์ชัน JavaScript ที่รับ props และคืนค่าเป็น JSX นับตั้งแต่ React 16.8 เป็นต้นมา ฮุกอนุญาตให้ใช้ state และ lifecycle ในคอมโพเนนต์แบบฟังก์ชันได้ ```jsx // Functional component (recommended) // More concise, easier to test, supports hooks function Welcome({ name }) { const [visits, setVisits] = useState(0) useEffect(() => { setVisits(v => v + 1) }, []) return

Hello {name}, visit #{visits}

} // Class component (legacy) // More verbose, requires this binding class WelcomeClass extends React.Component { state = { visits: 0 } componentDidMount() { this.setState(prev => ({ visits: prev.visits + 1 })) } render() { return

Hello {this.props.name}, visit #{this.state.visits}

} } ``` ปัจจุบันคอมโพเนนต์แบบฟังก์ชันถือเป็นมาตรฐาน คอมโพเนนต์แบบคลาสยังคงรองรับอยู่แต่ไม่แนะนำสำหรับโปรเจกต์ใหม่ ### 3. JSX ทำงานอย่างไร JSX คือส่วนขยายไวยากรณ์ของ JavaScript ที่อนุญาตให้เขียนมาร์กอัปภายในโค้ด JSX ไม่ใช่ HTML แต่เป็น JavaScript ในรูปแบบที่อ่านง่ายกว่า ```jsx // What we write (JSX) const element = (

Title

Paragraph

) // What Babel compiles (pure JavaScript) const element = React.createElement( 'div', { className: 'container' }, React.createElement('h1', null, 'Title'), React.createElement('p', null, 'Paragraph') ) ``` ความแตกต่างจาก HTML ได้แก่ การใช้ `className` แทน `class`, `htmlFor` แทน `for`, การใช้ camelCase สำหรับแอตทริบิวต์ (`onClick`, `tabIndex`) และต้องปิดแท็กที่ปิดในตัวเองเสมอ ### 4. state กับ props ต่างกันอย่างไร Props คือข้อมูลที่ส่งจากคอมโพเนนต์แม่ไปยังลูก เป็นข้อมูลที่อ่านได้อย่างเดียว ส่วน state คือสถานะภายในของคอมโพเนนต์ที่สามารถเปลี่ยนแปลงผ่าน setter ได้ ```jsx // UserCard.jsx // name and role are props (immutable) function UserCard({ name, role }) { // isExpanded is state (mutable) const [isExpanded, setIsExpanded] = useState(false) return (

{name}

{role}

{/* Modifying state triggers a re-render */} {isExpanded && }
) } // Usage ``` หลักการพื้นฐานคือ props ไหลจากบนลงล่าง (พ่อแม่ไปยังลูก) ส่วน state เป็นของแต่ละคอมโพเนนต์โดยเฉพาะ ### 5. ทำไม key ในรายการจึงสำคัญ Key ช่วยให้ React ระบุได้ว่ามีองค์ประกอบใดเปลี่ยนแปลง เพิ่ม หรือถูกลบออกจากรายการ หากไม่มี key ที่ไม่ซ้ำและคงที่ React อาจแสดงพฤติกรรมที่ไม่คาดคิด ```jsx // ❌ Bad practice: index as key // Problem: if order changes, React loses tracking {items.map((item, index) => ( ))} // ✅ Good practice: unique and stable identifier {items.map(item => ( ))} // Concrete example of the problem with indices function TodoList() { const [todos, setTodos] = useState([ { id: 1, text: 'Learn React' }, { id: 2, text: 'Create a project' } ]) // When deleting the first element with key={index} // React will think element 0's content changed // instead of understanding an element was removed return (
    {todos.map(todo => (
  • {todo.text}
  • ))}
) } ``` ## React Hooks ### 6. อธิบาย useState และข้อผิดพลาดที่พบบ่อย `useState` ใช้จัดการ state ภายในคอมโพเนนต์แบบฟังก์ชัน setter รับได้ทั้งค่าใหม่หรือฟังก์ชันสำหรับอัปเดต ```jsx // Declaration with initial value const [count, setCount] = useState(0) // ❌ Pitfall: multiple updates in the same cycle function increment() { setCount(count + 1) // count = 0, sets 1 setCount(count + 1) // count = 0 still, sets 1 setCount(count + 1) // count = 0 still, sets 1 // Final result: 1 (not 3) } // ✅ Solution: use the update function function incrementCorrect() { setCount(prev => prev + 1) // 0 → 1 setCount(prev => prev + 1) // 1 → 2 setCount(prev => prev + 1) // 2 → 3 // Final result: 3 } // ❌ Pitfall: object mutation const [user, setUser] = useState({ name: 'Alice', age: 25 }) user.age = 26 // Direct mutation, no re-render // ✅ Solution: create a new object setUser({ ...user, age: 26 }) // or setUser(prev => ({ ...prev, age: 26 })) ``` ### 7. useEffect ทำงานอย่างไรกับอาร์เรย์ของ dependency `useEffect` ทำงาน side effect หลังจากการเรนเดอร์ อาร์เรย์ของ dependency ควบคุมว่าเอฟเฟกต์จะถูกเรียกเมื่อใด ```jsx // Executed on every render (rare, usually avoid) useEffect(() => { console.log('Render completed') }) // Executed only on mount (equivalent to componentDidMount) useEffect(() => { console.log('Component mounted') // Cleanup on unmount (equivalent to componentWillUnmount) return () => { console.log('Component unmounted') } }, []) // Executed when userId changes useEffect(() => { async function fetchUser() { const response = await fetch(`/api/users/${userId}`) const data = await response.json() setUser(data) } fetchUser() }, [userId]) // ❌ Missing dependency - subtle bug useEffect(() => { const timer = setInterval(() => { setCount(count + 1) // count is "captured" at its initial value }, 1000) return () => clearInterval(timer) }, []) // count is missing from dependencies // ✅ Fix with update function useEffect(() => { const timer = setInterval(() => { setCount(prev => prev + 1) // No need for count in deps }, 1000) return () => clearInterval(timer) }, []) ``` > **กฎของ ESLint** > > ควรเปิดใช้งาน `eslint-plugin-react-hooks` เสมอเพื่อตรวจจับ dependency ที่ขาดหายไป กฎนี้ช่วยป้องกันบั๊กที่วินิจฉัยได้ยากจำนวนมาก ### 8. เมื่อใดควรใช้ useMemo และ useCallback ฮุกทั้งสองนี้ใช้สำหรับ memoization เพื่อหลีกเลี่ยงการคำนวณซ้ำหรือการสร้างค่าใหม่โดยไม่จำเป็น ควรระวังไม่ใช้มากเกินไป ```jsx // useMemo: memoizes a computed value function ProductList({ products, filter }) { // Recalculated only if products or filter change const filteredProducts = useMemo(() => { console.log('Filtering...') return products.filter(p => p.category === filter) }, [products, filter]) return
    {filteredProducts.map(p =>
  • {p.name}
  • )}
} // useCallback: memoizes a function function ParentComponent() { const [count, setCount] = useState(0) // Without useCallback, handleClick is recreated on every render // Causing unnecessary re-renders of ExpensiveChild const handleClick = useCallback((id) => { console.log('Clicked:', id) }, []) // Empty deps = stable function return ( <> {count} {/* React.memo on ExpensiveChild for this to be effective */} ) } // ❌ Over-optimization: not needed here const SimpleComponent = () => { // This calculation is trivial, useMemo adds overhead const doubled = useMemo(() => 2 * 2, []) return {doubled} } ``` ควรใช้ฮุกเหล่านี้เฉพาะเมื่อพบปัญหาด้านประสิทธิภาพที่ชัดเจน หรือเมื่อต้องการรักษา reference ที่ส่งให้กับคอมโพเนนต์ที่ถูก memoize ไว้ให้คงที่ ### 9. useRef ทำงานอย่างไรและใช้ในกรณีใดบ้าง `useRef` สร้าง reference ที่เปลี่ยนแปลงได้และคงอยู่ระหว่างการเรนเดอร์ โดยไม่ทำให้เกิดการเรนเดอร์ใหม่เมื่อมีการเปลี่ยนแปลงค่า ```jsx // Case 1: Access a DOM element function TextInput() { const inputRef = useRef(null) const focusInput = () => { inputRef.current.focus() } return ( <> ) } // Case 2: Store a mutable value without re-render function Timer() { const [seconds, setSeconds] = useState(0) const intervalRef = useRef(null) const start = () => { // Store the interval ID to be able to stop it intervalRef.current = setInterval(() => { setSeconds(s => s + 1) }, 1000) } const stop = () => { clearInterval(intervalRef.current) } return (
{seconds}s
) } // Case 3: Keep the previous value function usePrevious(value) { const ref = useRef() useEffect(() => { ref.current = value }, [value]) return ref.current } ``` ### 10. อธิบาย useContext และเมื่อใดควรใช้ `useContext` ช่วยให้เข้าถึง context ของ React โดยไม่ต้องส่ง props ทอดต่อกันหลายชั้น เหมาะสำหรับข้อมูลแบบ global เช่น ธีมหรือผู้ใช้ที่ล็อกอินอยู่ ```jsx // 1. Create the context const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} }) // 2. Create the provider function ThemeProvider({ children }) { const [theme, setTheme] = useState('light') const toggleTheme = useCallback(() => { setTheme(prev => prev === 'light' ? 'dark' : 'light') }, []) // Memoize the value to avoid unnecessary re-renders const value = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme]) return ( {children} ) } // 3. Use the context function ThemedButton() { const { theme, toggleTheme } = useContext(ThemeContext) return ( ) } // 4. Wrap the application function App() { return (