😎 React TypeScript

จัดการ State ซับซ้อนใน React ด้วย TypeScript และ useReducer ให้โค้ดสะอาดและปลอดภัย

5 นาที 14 views บันทึกเป็น PDF
จัดการ State ซับซ้อนใน React ด้วย TypeScript และ useReducer ให้โค้ดสะอาดและปลอดภัย

เบื่อไหมที่จัดการ State ใน React แล้วโค้ดมั่ว? มาดูวิธีใช้ useReducer คู่กับ Discriminated Unions เพื่อคุมการเปลี่ยนข้อมูลให้แม่นยำ ลดบั๊ก และเขียนโค้ดได้มือโปรขึ้น

ทำไมต้องใช้ useReducer กับ TypeScript ในโปรเจกต์ที่ซับซ้อน

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

ลองนึกภาพการสั่งอาหารในร้านอาหาร ถ้าเราสั่งทีละอย่างพนักงานอาจจะสับสน แต่ถ้าเรามี ใบสั่งอาหาร (รายการคำสั่งที่ระบุชัดเจน) พนักงานก็จะทำงานได้แม่นยำขึ้น useReducer ก็คือระบบที่เปลี่ยนข้อมูลตาม "ใบสั่ง" นี้เอง

การใช้คู่กับ TypeScript (ภาษาที่ช่วยตรวจสอบความผิดพลาดของโค้ด) จะทำให้เรามั่นใจว่าใบสั่งอาหารของเราไม่มีทางเขียนผิด เช่น ไม่เผลอใส่ข้อมูลที่ไม่จำเป็นเข้าไป ทำให้โค้ดของเราพังยากขึ้นมากตอนที่โปรเจกต์ใหญ่ขึ้น

รู้จักกับ Discriminated Unions เพื่อความปลอดภัยของข้อมูล

Discriminated Unions (การรวมประเภทข้อมูลโดยมีจุดสังเกต) คือเทคนิคการสร้างกฎว่า "ถ้าเลือกคำสั่งนี้ ต้องมีข้อมูลชุดนี้ตามมา" มันช่วยให้เราไม่เผลอใส่ข้อมูลมั่วซั่วลงไปในโปรแกรม

ลองจินตนาการถึงตู้จดหมาย ถ้าเราติดป้ายหน้าตู้ว่า "จดหมายด่วน" ต้องมี "ที่อยู่ผู้ส่ง" แต่ถ้าเป็น "โฆษณา" ไม่ต้องมีที่อยู่ การใช้ type เป็นตัวแยกประเภทข้อมูลแบบนี้ จะช่วยให้โปรแกรมรู้ทันทีว่าต้องเช็กข้อมูลส่วนไหนบ้าง

หากเราไม่ใช้เทคนิคนี้ เวลาเขียนโค้ดเราอาจจะลืมใส่ข้อมูลสำคัญไป ทำให้ตอนรันโปรแกรมแล้วเกิดบั๊ก (ข้อผิดพลาดของโค้ด) ได้ง่าย การกำหนดกฎแบบนี้จึงเป็นเหมือน เกราะป้องกัน ให้เราเขียนโค้ดได้มั่นใจขึ้น

// กำหนดรูปแบบของ Action (คำสั่งที่ส่งไปเปลี่ยนสถานะ)
type TodoAction = 
  | { type: 'ADD'; payload: { id: number; text: string } }
  | { type: 'DELETE'; id: number };

// ตัวอย่างนี้คือการบอกว่า 
// ถ้า type เป็น 'ADD' ต้องมี payload 
// แต่ถ้าเป็น 'DELETE' ต้องมีแค่ id เท่านั้น

ในโค้ดด้านบน เราได้กำหนดกฎเหล็กไว้แล้วว่าคำสั่ง ADD ต้องมาคู่กับข้อมูล payload (ข้อมูลที่ต้องการเพิ่ม) เสมอ ส่วนคำสั่ง DELETE จะสนใจแค่ id (เลขระบุตัวตนของข้อมูล) เท่านั้น

วิธีเขียน useReducer ให้ทำงานกับกฎของเรา

เมื่อเรามีกฎแล้ว ขั้นตอนถัดไปคือการสร้างฟังก์ชันที่จะคอยรับคำสั่งไปทำงานจริง เราต้องทำให้ฟังก์ชันนี้ฉลาดพอที่จะรู้ว่า "ถ้าได้รับคำสั่งแบบนี้ ต้องทำอย่างไร" โดยใช้ switch (คำสั่งเลือกเงื่อนไข) เป็นตัวตรวจสอบ

  1. สร้างฟังก์ชัน reducer ที่รับสถานะปัจจุบันและคำสั่งเข้ามา
  2. ใช้ switch เช็กค่า action.type เพื่อตัดสินใจว่าจะทำอะไร
  3. ส่งค่าสถานะใหม่กลับออกไปเสมอ เพื่อให้หน้าจอแสดงผลได้ถูกต้อง
function todoReducer(state: Todo[], action: TodoAction) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.payload];
    case 'DELETE':
      return state.filter(todo => todo.id !== action.id);
    default:
      return state; // คืนค่าเดิมถ้าไม่เจอคำสั่งที่ตรงกัน
  }
}

สังเกตว่า TypeScript จะช่วยเราได้มาก หากเราพยายามส่งข้อมูลผิดกฎใน action ระบบจะแจ้งเตือนทันทีตั้งแต่วันที่เรากำลังเขียนโค้ด ไม่ต้องรอให้ไปพังตอนรันจริง

จุดที่มือใหม่มักพลาดและวิธีแก้ไข

สิ่งที่มือใหม่มักพลาดคือการลืมใส่ default (กรณีที่ไม่ตรงกับเงื่อนไขใดเลย) ใน switch หรือลืมระบุประเภทข้อมูลของ state ให้ชัดเจนตั้งแต่ต้น ทำให้โปรแกรมทำงานไม่สมบูรณ์

อีกเรื่องคือการพยายามเปลี่ยนค่าสถานะเดิมโดยตรง ซึ่งถือเป็นเรื่องห้ามทำใน React (เครื่องมือสร้างหน้าเว็บ) เราต้องสร้างข้อมูลชุดใหม่ขึ้นมาเสมอ เช่น การใช้ ...state (การก๊อปปี้ข้อมูลเดิม) เพื่อสร้างรายการใหม่

ถ้าคุณกำลังฝึกเขียน ให้ลองเริ่มจากโปรเจกต์เล็ก ๆ อย่าง To-Do List (รายการสิ่งที่ต้องทำ) ก่อน อย่าเพิ่งรีบข้ามไปทำระบบที่ซับซ้อนเกินไป การฝึกให้ชินกับกฎของ useReducer จะทำให้คุณทำงานกับทีมได้ง่ายขึ้นในอนาคต

สรุป: เอาไปใช้จริงในงานพัฒนา

การใช้ Discriminated Unions ร่วมกับ useReducer เป็นทักษะสำคัญที่ทำให้โค้ดของคุณดูเป็นมืออาชีพ มันช่วยลดบั๊กที่เกิดจากการลืมใส่ข้อมูล และทำให้คนอื่นในทีมอ่านโค้ดของคุณได้ง่ายขึ้นมาก

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

การเป็นโปรแกรมเมอร์ที่ดีไม่ได้วัดกันที่เขียนโค้ดเร็วแค่ไหน แต่อยู่ที่การเขียนโค้ดให้ อ่านง่ายและแก้ไขได้ปลอดภัย ในระยะยาวครับ ขอให้สนุกกับการฝึกฝนและทำความเข้าใจเครื่องมือเหล่านี้ให้แม่นยำนะครับ

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

วิธีเช็ก Type ด้วย tsc --noEmit และตั้งค่า Environment Variables ใน React TypeScript ก่อน Deploy
React TypeScript

วิธีเช็ก Type ด้วย tsc --noEmit และตั้งค่า Environment Variables ใน React TypeScript ก่อน Deploy

ไม่อยากให้แอปพังตอน Deploy ต้องอ่าน! สอนวิธีใช้ tsc --noEmit ตรวจสอบข้อผิดพลาดในโปรเจกต์ React TypeScript พร้อมวิธีตั้งค่า Environment Variables ให้ปลอดภัย

1 month ago 8 นาที
22 views
React TypeScript Workshop: จัดการ State, Form และ API ให้ปลอดภัยแบบมือโปร
React TypeScript

React TypeScript Workshop: จัดการ State, Form และ API ให้ปลอดภัยแบบมือโปร

เรียนรู้วิธีเขียน React ด้วย TypeScript ให้โค้ดสะอาดและลดบั๊ก ตั้งแต่การจัดการ Form ด้วย React Hook Form ไปจนถึงการดึงข้อมูล API และทำ Global State แบบ Type Safe

1 month ago 8 นาที
24 views
React TypeScript Workshop: เริ่มต้นเขียนโค้ดแบบมือโปรด้วย Type-First Architecture
React TypeScript

React TypeScript Workshop: เริ่มต้นเขียนโค้ดแบบมือโปรด้วย Type-First Architecture

อยากเขียน React ให้เก่งและบั๊กน้อยลงไหม? มาเรียนรู้วิธีวางโครงสร้างข้อมูล (Type-First) และสร้าง UI Component ที่นำกลับมาใช้ใหม่ได้จริง

1 month ago 7 นาที
23 views