Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

การสร้าง Component ที่ Reusable ด้วย Material UI

บทความนี้กล่าวถึงการสร้าง Reusable Component ด้วย Material UI ซึ่งเป็นหัวใจสำคัญของการพัฒนา Frontend ที่มีประสิทธิภาพ โดยเน้นที่การสร้าง Custom Component ด้วยกา...

การสร้าง Component ที่ Reusable ด้วย Material UI

ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการปรับแต่ง Theme และ Style ใน Material UI เพื่อให้ Component ต่างๆ ดูเป็นไปในทิศทางเดียวกันและเข้ากับ Design System ของโปรเจกต์เรา ในบทนี้ เราจะก้าวไปอีกขั้นด้วยการเรียนรู้วิธีการสร้าง Component ที่สามารถนำกลับมาใช้ใหม่ได้ (Reusable Component) ซึ่งเป็นหัวใจสำคัญของการพัฒนา Frontend ที่มีประสิทธิภาพและบำรุงรักษาง่าย

Reusable Component คือ Component ที่ถูกออกแบบมาให้สามารถนำไปใช้ในหลายๆ ที่ของแอปพลิเคชันได้ โดยไม่ต้องเขียนโค้ดซ้ำๆ ทำให้โค้ดของเราสะอาด อ่านง่าย และง่ายต่อการแก้ไขเมื่อต้องการเปลี่ยนแปลงอะไรบางอย่าง Material UI มี Component พื้นฐานให้เราใช้งานมากมาย แต่ในบางครั้งเราก็ต้องการ Component ที่มีความเฉพาะเจาะจงกับโปรเจกต์ของเรา การสร้าง Custom Component ที่ Reusable จึงเป็นสิ่งจำเป็น

ทำไมต้องสร้าง Reusable Component?

  • ลดความซ้ำซ้อนของโค้ด: ไม่ต้องเขียนโค้ดเดิมซ้ำๆ ในหลายๆ ที่
  • เพิ่มความสามารถในการบำรุงรักษา: แก้ไข Component เพียงที่เดียว การเปลี่ยนแปลงจะส่งผลไปยังทุกที่ที่ Component นั้นถูกใช้งาน
  • เพิ่มความสอดคล้องของ UI: Component ทุกตัวมีลักษณะและการทำงานที่เหมือนกัน ทำให้ UI ของแอปพลิเคชันมีความสอดคล้องกัน
  • เพิ่มประสิทธิภาพการพัฒนา: สามารถนำ Component ที่สร้างไว้แล้วไปใช้งานได้ทันที ช่วยลดเวลาในการพัฒนา

การสร้าง Custom Component

การสร้าง Custom Component ใน React (และ Material UI) ทำได้โดยการสร้าง Function Component หรือ Class Component แล้วนำ Material UI Component มาประกอบรวมกัน หรือปรับแต่ง Material UI Component ให้ตรงกับความต้องการของเรา

ตัวอย่าง: สร้าง Custom Button Component

สมมติว่าเราต้องการสร้าง Button Component ที่มี Style เฉพาะตัว และมีการใช้งานบ่อยในโปรเจกต์ของเรา เราสามารถสร้าง Custom Button Component ได้ดังนี้:

import React from 'react';
import { Button, makeStyles } from '@material-ui/core';

const useStyles = makeStyles((theme) => ({
  customButton: {
    backgroundColor: theme.palette.primary.main,
    color: theme.palette.primary.contrastText,
    '&:hover': {
      backgroundColor: theme.palette.primary.dark,
    },
  },
}));

function CustomButton(props) {
  const classes = useStyles();
  const { children, ...other } = props;

  return (
    <Button className={classes.customButton} {...other}>
      {children}
    </Button>
  );
}

export default CustomButton;

คำอธิบาย:

  • เรา import `Button` และ `makeStyles` จาก Material UI
  • เราสร้าง Style ด้วย `makeStyles` โดยกำหนด Style สำหรับ Button ของเราภายใต้ class `customButton`
  • เราสร้าง Function Component ชื่อ `CustomButton`
  • ภายใน `CustomButton` เราใช้ `useStyles` เพื่อให้ได้ classes ที่เรากำหนดไว้
  • เราส่ง `children` และ `...other` props ไปยัง Material UI Button เพื่อให้ Button ของเราสามารถรับ props อื่นๆ ได้เหมือน Button ทั่วไป
  • เรานำ class `customButton` มาใส่ให้กับ Material UI Button

การใช้งาน Custom Button Component:

import React from 'react';
import CustomButton from './CustomButton';

function MyComponent() {
  return (
    <CustomButton onClick={() => alert('Button Clicked!')}>
      Click Me!
    </CustomButton>
  );
}

export default MyComponent;

ข้อดีของการสร้าง Custom Component แบบนี้:

  • แยกส่วน Style: Style ของ Button ถูกแยกออกจาก Component อื่นๆ ทำให้ง่ายต่อการแก้ไข
  • Reusable: สามารถนำ `CustomButton` ไปใช้ในหลายๆ ที่ได้ โดยไม่ต้องเขียน Style ซ้ำ
  • Maintainable: หากต้องการเปลี่ยน Style ของ Button สามารถแก้ไขได้ที่ `CustomButton` ที่เดียว

การใช้ Props และ State

Props และ State เป็นสิ่งสำคัญในการสร้าง Reusable Component เพราะช่วยให้ Component สามารถรับข้อมูลจากภายนอกและจัดการข้อมูลภายในได้

Props: ใช้สำหรับส่งข้อมูลจาก Component แม่ (Parent Component) ไปยัง Component ลูก (Child Component) Props มีลักษณะเป็น Read-Only (แก้ไขไม่ได้จากภายใน Child Component)

State: ใช้สำหรับเก็บข้อมูลที่ Component ต้องการจัดการเอง State สามารถเปลี่ยนแปลงได้จากภายใน Component เอง

ตัวอย่าง: สร้าง Custom Input Component

import React, { useState } from 'react';
import { TextField } from '@material-ui/core';

function CustomInput(props) {
  const { label, ...other } = props;
  const [value, setValue] = useState('');

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <TextField
      label={label}
      value={value}
      onChange={handleChange}
      {...other}
    />
  );
}

export default CustomInput;

คำอธิบาย:

  • เรา import `TextField` จาก Material UI
  • เราใช้ `useState` Hook เพื่อสร้าง State ชื่อ `value` ซึ่งเก็บค่าของ Input
  • เราสร้าง Function `handleChange` เพื่ออัปเดตค่าของ `value` เมื่อมีการพิมพ์ใน Input
  • เราส่ง `label` prop ไปยัง Material UI TextField เพื่อกำหนด Label ของ Input
  • เราส่ง `value` และ `onChange` ไปยัง Material UI TextField เพื่อควบคุมค่าของ Input
  • เราส่ง `...other` props ไปยัง Material UI TextField เพื่อให้ Input ของเราสามารถรับ props อื่นๆ ได้เหมือน TextField ทั่วไป

การใช้งาน Custom Input Component:

import React from 'react';
import CustomInput from './CustomInput';

function MyComponent() {
  return (
    <CustomInput label="Name" variant="outlined" />
  );
}

export default MyComponent;

การจัดการ Event

การจัดการ Event เป็นสิ่งจำเป็นในการสร้าง Component ที่มีการโต้ตอบกับผู้ใช้ เราสามารถใช้ Props เพื่อส่ง Function จาก Parent Component ไปยัง Child Component และให้ Child Component เรียก Function นั้นเมื่อเกิด Event ที่ต้องการ

ตัวอย่าง: การจัดการ Event ใน Custom Button Component (ปรับปรุงจากตัวอย่างก่อนหน้า)

import React from 'react';
import { Button, makeStyles } from '@material-ui/core';

const useStyles = makeStyles((theme) => ({
  customButton: {
    backgroundColor: theme.palette.primary.main,
    color: theme.palette.primary.contrastText,
    '&:hover': {
      backgroundColor: theme.palette.primary.dark,
    },
  },
}));

function CustomButton(props) {
  const classes = useStyles();
  const { children, onClick, ...other } = props;

  return (
    <Button className={classes.customButton} onClick={onClick} {...other}>
      {children}
    </Button>
  );
}

export default CustomButton;

คำอธิบาย:

  • เราเพิ่ม `onClick` prop ให้กับ `CustomButton`
  • เราส่ง `onClick` prop ไปยัง Material UI Button

การใช้งาน Custom Button Component:

import React from 'react';
import CustomButton from './CustomButton';

function MyComponent() {
  const handleClick = () => {
    alert('Button Clicked!');
  };

  return (
    <CustomButton onClick={handleClick}>
      Click Me!
    </CustomButton>
  );
}

export default MyComponent;

การสร้าง Component ที่มี Logic ซับซ้อน

ในบางครั้ง เราอาจต้องการสร้าง Component ที่มี Logic ซับซ้อน เช่น การดึงข้อมูลจาก API หรือการจัดการ State ที่ซับซ้อน ในกรณีนี้ เราสามารถใช้ Hooks ต่างๆ ของ React เช่น `useState`, `useEffect`, `useContext` หรือ Custom Hooks เพื่อจัดการ Logic เหล่านั้น

ตัวอย่าง: สร้าง Custom Data Fetching Component (ตัวอย่างนี้อาจซับซ้อนเกินไปสำหรับระดับ Intermediate แต่เป็นตัวอย่างที่ดีในการแสดงให้เห็นถึงการจัดการ Logic ที่ซับซ้อน)

import React, { useState, useEffect } from 'react';
import { Typography } from '@material-ui/core';

function DataFetchingComponent({ apiUrl }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(apiUrl);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [apiUrl]); // useEffect จะทำงานเมื่อ apiUrl เปลี่ยนแปลง

  if (loading) {
    return <Typography>Loading...</Typography>;
  }

  if (error) {
    return <Typography color="error">Error: {error.message}</Typography>;
  }

  return (
    <Typography>Data: {JSON.stringify(data)}</Typography>
  );
}

export default DataFetchingComponent;

คำอธิบาย:

  • เราใช้ `useState` เพื่อจัดการ State ของ Data, Loading และ Error
  • เราใช้ `useEffect` เพื่อดึงข้อมูลจาก API เมื่อ Component ถูก Mount
  • เราใช้ `try...catch...finally` เพื่อจัดการ Error และ Loading State

การใช้งาน Custom Data Fetching Component:

import React from 'react';
import DataFetchingComponent from './DataFetchingComponent';

function MyComponent() {
  return (
    <DataFetchingComponent apiUrl="https://jsonplaceholder.typicode.com/todos/1" />
  );
}

export default MyComponent;

ข้อควรจำในการสร้าง Reusable Component

  • Keep it Simple: พยายามทำให้ Component ทำงานอย่างใดอย่างหนึ่ง (Single Responsibility)
  • Use Props Wisely: กำหนด Props ที่จำเป็นเท่านั้น และตั้งชื่อ Props ให้สื่อความหมาย
  • Document Your Components: เขียน Comment อธิบายการทำงานของ Component และ Props ต่างๆ
  • Test Your Components: เขียน Unit Test เพื่อให้มั่นใจว่า Component ทำงานได้อย่างถูกต้อง

การสร้าง Reusable Component เป็นทักษะที่สำคัญในการพัฒนา Frontend ด้วย Material UI และ React การฝึกฝนและทำความเข้าใจแนวคิดเหล่านี้จะช่วยให้คุณสร้างแอปพลิเคชันที่มีประสิทธิภาพและบำรุงรักษาง่ายขึ้น ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับการใช้งาน Ant Design ซึ่งเป็น Component Library ยอดนิยมอีกตัวหนึ่ง

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service