Functional Component ใน React — มาตรฐานการพัฒนาสมัยใหม่

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

Functional Component — เป็นวิธีการสร้างคอมโพเนนต์ React โดยใช้ฟังก์ชัน JavaScript ทั่วไป ซึ่งกลายเป็นมาตรฐานหลังจาก React 16.8 เปิดตัวและมีการนำฮุคมาใช้ คอมโพเนนต์แบบฟังก์ชันรับ props และส่งคืนอิลิเมนต์ React โดยไม่ต้องสืบทอดจาก React.Component ตามข้อมูลจาก React, 2024 พบว่า 97% ของคอมโพเนนต์ใหม่ในระบบนิเวศ React ถูกเขียนเป็นฟังก์ชัน

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

  • Functional Component — ฟังก์ชัน JavaScript ทั่วไปที่รับ props และส่งคืน JSX โดยไม่ต้อง extends Component
  • ฮุค (useState, useEffect, useContext) ให้คอมโพเนนต์แบบฟังก์ชันสามารถเข้าถึงสเตตและวงจรชีวิตได้อย่างเต็มที่
  • ความอ่านง่าย — คอมโพเนนต์แบบฟังก์ชันสั้นกว่าคอมโพเนนต์แบบคลาส ไม่ต้องมี constructor, bind และเมธอดวงจรชีวิตที่เกินจำเป็น
  • ประสิทธิภาพ — React ปรับแต่งคอมโพเนนต์แบบฟังก์ชันผ่าน memoization และการเริ่มต้นแบบขี้เกียจ
  • คำแนะนำของ React — โปรเจกต์ใหม่ทั้งหมดควรใช้เฉพาะคอมโพเนนต์แบบฟังก์ชันกับฮุค

Functional Component คืออะไร?

Functional Component คือคอมโพเนนต์ React ที่ถูกกำหนดเป็นฟังก์ชัน ซึ่งรับออบเจกต์ props และส่งคืนอิลิเมนต์ React ก่อน React 16.8 คอมโพเนนต์เหล่านี้ถูกเรียกว่า stateless เพราะไม่สามารถจัดการสเตตภายในได้

ด้วยการนำ ฮุค มาใช้ใน React 16.8 (กุมภาพันธ์ 2019) คอมโพเนนต์แบบฟังก์ชันสามารถเข้าถึงสเตต (useState) เอฟเฟกต์ข้างเคียง (useEffect) บริบท (useContext) และ ref (useRef) คำว่า “stateless” ล้าสมัยแล้ว — คอมโพเนนต์แบบฟังก์ชันสมัยใหม่จัดการสเตตได้อย่างสมบูรณ์

React แนะนำอย่างเป็นทางการให้คอมโพเนนต์แบบฟังก์ชันเป็น วิธีหลัก ในการสร้างคอมโพเนนต์ เอกสารทั้งหมดบน react.dev, ตัวอย่าง, บทช่วยสอน และ API ใหม่ (Server Components, Actions) สร้างขึ้นบนแนวทางแบบฟังก์ชัน คอมโพเนนต์แบบคลาสไม่ได้ถูกลบออก แต่คุณสมบัติใหม่ของ React มีให้ใช้ผ่านฮุคเท่านั้น

การสร้าง Functional Component

คอมโพเนนต์แบบฟังก์ชันที่ง่ายที่สุดคือฟังก์ชันที่ส่งคืน JSX มันรับ props เป็นอาร์กิวเมนต์ ไม่ต้องใช้ constructor, การเรียก super หรือการผูก this Props สามารถเข้าถึงได้ โดยตรงผ่านอาร์กิวเมนต์ของฟังก์ชัน — ไม่ต้องใช้ this.props

js
// Functional component without state
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

// Arrow function (common variant)
const Greeting = ({ name }) => (
  <h1>Hello, {name}!</h1>
);

คอมโพเนนต์ที่มีสเตต

เพื่อเพิ่มสเตต ให้ใช้ useState ฮุคส่งคืนทูเพิลของสองค่า: สเตตปัจจุบันและฟังก์ชัน setter แตกต่างจาก this.setState แบบคลาส useState แทนที่ค่าทั้งหมดแทนที่จะรวมกับค่าก่อนหน้า

js
import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

ฮุคใน Functional Component

ฮุคเป็นรากฐานของ React สมัยใหม่ ฮุคแต่ละตัวแก้ไขงานเฉพาะ: useState — สเตต, useEffect — เอฟเฟกต์ข้างเคียง, useContext — การเข้าถึงบริบท, useRef — การอ้างอิงอิลิเมนต์ DOM, useCallback และ useMemo — memoization

useEffect สำหรับเอฟเฟกต์ข้างเคียง

useEffect แทนที่ componentDidMount, componentDidUpdate และ componentWillUnmount พร้อมกัน อาร์กิวเมนต์แรกคือ callback ที่มีเอฟเฟกต์ อาร์กิวเมนต์ที่สองคืออาร์เรย์ของ dependencies ถ้าอาร์เรย์ว่างเปล่า เอฟเฟกต์จะทำงานครั้งเดียวหลังจาก mount ถ้ามีการระบุ dependencies เอฟเฟกต์จะทำงานเมื่อใดก็ตามที่มีการเปลี่ยนแปลง

js
import React, { useState, useEffect } from 'react';

function UserData({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    let cancelled = false;

    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => {
        if (!cancelled) setUser(data);
      });

    // Cleanup - analog of componentWillUnmount
    return () => { cancelled = true; };
  }, [userId]); // Dependency

  return <div>{user?.name}</div>;
}

Custom Hooks

ข้อได้เปรียบหลักของคอมโพเนนต์แบบฟังก์ชันคือ การใช้ลอจิกซ้ำ ผ่าน custom hooks ในขณะที่คอมโพเนนต์แบบคลาส ลอจิกถูกทำซ้ำระหว่าง componentDidMount และ componentDidUpdate ในคอมโพเนนต์แบบฟังก์ชัน ลอจิกจะถูกแยกออกเป็นฟังก์ชันแยกต่างหากที่มีคำนำหน้า use Custom hooks เป็นทางเลือกหลักแทน HOC และ render props

การประกอบแทนการสืบทอด

React แนะนำ การประกอบ แทนการสืบทอดเพื่อการใช้โค้ดซ้ำระหว่างคอมโพเนนต์ คอมโพเนนต์แบบฟังก์ชันเหมาะสำหรับการประกอบ: คอมโพเนนต์หนึ่งสามารถมีคอมโพเนนต์อื่นหลายตัว โดยส่ง props และ children ให้พวกมัน

แพทเทิร์น children — เมื่อคอมโพเนนต์รับอิลิเมนต์ลูกผ่าน prop children — ถูกใช้งานอย่างเป็นธรรมชาติ: function Layout({ children }) สิ่งที่คล้าย slots ของ Vue ถูกใช้งานผ่าน props คอมโพเนนต์ที่มีชื่อ: function Page({ header, sidebar, content })

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

การปรับแต่งประสิทธิภาพ

คอมโพเนนต์แบบฟังก์ชันมาพร้อมกับกลไกการปรับแต่งในตัว React.memo — เทียบเท่า PureComponent สำหรับฟังก์ชัน: ป้องกันการเรนเดอร์ใหม่ถ้า props ไม่เปลี่ยนแปลง (การเปรียบเทียบระดับพื้นผิว) useMemo แคชผลลัพธ์ของการคำนวณระหว่างการเรนเดอร์

js
import React, { useMemo } from 'react';

// React.memo - memoize component
const ExpensiveList = React.memo(({ items }) => {
  return <ul>
    {items.map(item =>
      <li key={item.id}>{item.name}</li>
    )}
  </ul>;
});

// useMemo - caching result
function Dashboard({ transactions }) {
  const summary = useMemo(() => {
    return transactions.reduce((acc, t) => acc + t.amount, 0);
  }, [transactions]);

  return <p>Total: {summary}</p>;
}

useCallback memoize ฟังก์ชัน callback เพื่อไม่ให้ถูกสร้างใหม่ทุกครั้งที่เรนเดอร์ นี่เป็นสิ่งสำคัญเมื่อส่งฟังก์ชันไปยังคอมโพเนนต์ลูกที่หุ้มด้วย React.memo: หากไม่มี useCallback คอมโพเนนต์ลูกจะถูกเรนเดอร์ใหม่ทุกครั้งเพราะการอ้างอิงฟังก์ชันเปลี่ยนไป

Functional vs Class Component

ความแตกต่างระหว่างแนวทางทั้งสองเกินกว่ารูปแบบไวยากรณ์ คอมโพเนนต์แบบฟังก์ชัน คือ closure: สเตตและเอฟเฟกต์ถูกผูกกับเรนเดอร์เฉพาะ คอมโพเนนต์แบบคลาส ใช้ this: สเตตถูกดึงจาก this.state เสมอ ซึ่งอาจล้าสมัยเมื่อ callback แบบอะซิงโครนัสทำงาน

ด้านฟังก์ชันคลาส
สเตตuseState (แยกอิสระ)this.state + this.setState
เอฟเฟกต์useEffect พร้อม dependenciescomponentDidMount + componentDidUpdate
บริบทuseContextContext.Consumer หรือ static contextType
การปรับแต่งReact.memo + useMemoPureComponent + shouldComponentUpdate
การใช้ลอจิกซ้ำCustom hooksHOC / Render props
thisไม่มีbind ใน constructor

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

TypeScript และ Functional Component

TypeScript ทำงานเป็นธรรมชาติมากกว่ากับคอมโพเนนต์แบบฟังก์ชันเมื่อเทียบกับคลาส การกำหนดชนิด props — อินเทอร์เฟซสำหรับอาร์กิวเมนต์ของฟังก์ชัน ชนิดที่ส่งคืนคือ JSX.Element หรือ ReactNode useState อนุมานชนิดจากค่าเริ่มต้นโดยอัตโนมัติ

ts
import React, { useState } from 'react';

interface ButtonProps {
  label: string;
  variant?: 'primary' | 'secondary';
  onClick: () => void;
}

const Button: React.FC<ButtonProps> =
  ({ label, variant = 'primary', onClick }) => (
    <button
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {label}
    </button>
  );

TypeScript สมัยใหย่ช่วยให้กำหนดชนิด useReducer ด้วยชนิด union แบบแยกแยะ, Generics ใน custom hooks และการตรวจสอบ children อย่างเข้มงวดผ่าน React.PropsWithChildren คอมโพเนนต์แบบฟังก์ชันกับ TypeScript ให้ความปลอดภัยของชนิดอย่างสมบูรณ์โดยไม่มีนามธรรมเพิ่มเติม

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

ทำไม React ถึงแนะนำคอมโพเนนต์แบบฟังก์ชัน?

คอมโพเนนต์แบบฟังก์ชัน ง่ายกว่า: ไม่มี constructor, bind, this หรือเมธอดวงจรชีวิตที่กระจายอยู่ ฮุคช่วยให้จัดกลุ่มลอจิกที่เกี่ยวข้องได้ React ลงทุนทรัพยากรในการพัฒนาฮุค ไม่ใช่คลาส Server Components และคุณสมบัติใหม่มีให้ใช้เฉพาะในฟังก์ชันเท่านั้น

ฉันสามารถใช้ setInterval ในคอมโพเนนต์แบบฟังก์ชันได้ไหม?

ได้ ผ่าน useEffect โดยมีตัวจับเวลาภายในและฟังก์ชันทำความสะอาดสำหรับ clearInterval โปรดระวัง closure: ถ้าคุณเพิ่มค่าตัวนับ ให้ใช้รูปแบบฟังก์ชันของ setState: setCount(c => c + 1) เพื่อไม่ให้ขึ้นอยู่กับค่าเก่าใน closure

จะรับ props ก่อนหน้าในคอมโพเนนต์แบบฟังก์ชันได้อย่างไร?

ใช้ useRef เพื่อเก็บค่าก่อนหน้า อัปเดต ref ใน useEffect หลังจากการเรนเดอร์แต่ละครั้ง Custom hook usePrevious ช่วยในการเปรียบเทียบ: const prev = usePrevious(value);

React.memo แตกต่างจาก useMemo อย่างไร?

React.memo คือ HOC สำหรับ memoize ทั้งคอมโพเนนต์: ป้องกันการเรนเดอร์ใหม่ถ้า props ไม่เปลี่ยนแปลง useMemo คือฮุคสำหรับ memoize ค่าเฉพาะภายในคอมโพเนนต์: แคชผลลัพธ์ของฟังก์ชันระหว่างการเรนเดอร์ตามอาร์เรย์ของ dependencies

จะจำลอง getDerivedStateFromProps ในคอมโพเนนต์แบบฟังก์ชันได้อย่างไร?

วิธีที่ง่ายที่สุดคือ useState ที่มีการเริ่มต้นจาก props + useEffect ที่มี dependency กับ props เพื่อการซิงค์ สำหรับกรณีที่พบไม่บ่อย React แนะนำให้ใช้ key เพื่อบังคับให้สร้างคอมโพเนนต์ใหม่เมื่อข้อมูลนำเข้าเปลี่ยนแปลง

สรุป

  • Functional Component — มาตรฐาน React สมัยใหม่: ฟังก์ชันที่รับ props และส่งคืน JSX
  • ฮุค (useState, useEffect) ให้คอมโพเนนต์แบบฟังก์ชันมีสเตต เอฟเฟกต์ และบริบทโดยไม่ต้องใช้คลาส
  • การประกอบ ผ่าน children และ custom hooks แทนที่การสืบทอดและแพทเทิร์น HOC
  • React.memo และ useMemo ให้การปรับแต่งประสิทธิภาพสำหรับคอมโพเนนต์แบบฟังก์ชัน
  • TypeScript กับคอมโพเนนต์แบบฟังก์ชันให้การกำหนดชนิด props ที่เข้มงวดและการอนุมานชนิดอัตโนมัติ
  • useEffect แทนที่เมธอดวงจรชีวิตทั้งหมดของคอมโพเนนต์แบบคลาสในที่เดียว
  • Custom hooks ช่วยให้แยกและใช้ลอจิกซ้ำระหว่างคอมโพเนนต์โดยไม่ต้องใช้ HOC

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

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

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

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