본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

การจัดการ State ของข้อมูลที่ได้จาก API

บทนี้จะกล่าวถึงวิธีการจัดการข้อมูลที่ได้จากการดึง API ใน React Native โดยเน้นที่การจัดการ State ด้วย `useState Hook` สำหรับ Component เดี่ยว และ `Context API` ส...

การจัดการ State ของข้อมูลที่ได้จาก API ใน React Native

หลังจากที่เราได้เรียนรู้วิธีการดึงข้อมูลจาก API ด้วย Fetch API ใน React Native กันไปแล้วในบทที่แล้ว (อย่าลืมว่าเราเน้นการใช้ GET method เพื่อดึงข้อมูลอย่างเดียวนะครับ) ในบทนี้เราจะมาเรียนรู้ถึงวิธีการจัดการข้อมูลเหล่านั้น หรือที่เรียกว่าการจัดการ State นั่นเองครับ เพราะการดึงข้อมูลมาอย่างเดียวไม่พอ เราต้องนำข้อมูลเหล่านั้นมาแสดงผลและอัพเดทใน UI ของแอปพลิเคชันเราด้วย

ใน React Native เรามีเครื่องมือหลักๆ สองตัวที่นิยมใช้ในการจัดการ State ได้แก่ useState Hook และ Context API ซึ่งแต่ละตัวก็มีข้อดีข้อเสียแตกต่างกันไป เราจะมาดูกันว่าแต่ละตัวทำงานอย่างไร และควรเลือกใช้ตัวไหนในสถานการณ์ใด

useState Hook: จัดการ State อย่างง่ายดายใน Component

useState Hook เป็น Hook ที่มาพร้อมกับ React ตั้งแต่เวอร์ชัน 16.8 เป็นต้นมา (React Native ก็ใช้ React เป็นพื้นฐาน ดังนั้นจึงใช้ได้แน่นอน) มันเป็นเครื่องมือที่ง่ายและสะดวกในการจัดการ State ภายใน Component เดียว ถ้าข้อมูลที่เราดึงมาจาก API จะถูกใช้แค่ใน Component นั้น และไม่ได้ซับซ้อนอะไรมาก useState คือตัวเลือกที่ดีที่สุดครับ

หลักการทำงานของ useState:

useState จะคืนค่ากลับมาเป็น Array ที่มีสองสมาชิก:

  • สมาชิกตัวแรก: ค่าของ State ปัจจุบัน (initial state ตอนเริ่มโปรแกรม หรือค่าที่ถูกอัพเดทล่าสุด)
  • สมาชิกตัวที่สอง: ฟังก์ชันสำหรับอัพเดทค่าของ State

ตัวอย่างการใช้งาน useState:

import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';

const App = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/todos'); // API สำหรับทดสอบ
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const json = await response.json();
        setData(json);
      } catch (error) {
        console.error('Error fetching data:', error);
      } finally {
        setLoading(false); // ไม่ว่าจะสำเร็จหรือล้มเหลว ให้หยุด Loading
      }
    };

    fetchData();
  }, []); // [] หมายถึง useEffect จะทำงานแค่ครั้งแรกที่ Component ถูก Mount เท่านั้น

  if (loading) {
    return (
      <View style={styles.container}>
        <Text>กำลังโหลดข้อมูล...</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <FlatList
        data={data}
        keyExtractor={(item) => item.id.toString()} // Convert id to string for key
        renderItem={({ item }) => (
          <View style={styles.item}>
            <Text>{item.title}</Text>
            <Text>Completed: {item.completed ? 'Yes' : 'No'}</Text>
          </View>
        )}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  item: {
    marginBottom: 10,
    padding: 10,
    borderWidth: 1,
    borderColor: '#ccc',
  },
});

export default App;

คำอธิบายโค้ด:

  • useState([]): เราสร้าง State ชื่อ data ให้มีค่าเริ่มต้นเป็น Array ว่างเปล่า ([]) เพราะเราคาดหวังว่า API จะส่งข้อมูลกลับมาเป็น Array
  • useState(true): เราสร้าง State ชื่อ loading ให้มีค่าเริ่มต้นเป็น true เพื่อบอกว่าแอปพลิเคชันกำลังโหลดข้อมูลอยู่
  • useEffect: Hook นี้จะทำงานหลังจาก Component ถูก Render ครั้งแรก เราใช้มันเพื่อเรียกฟังก์ชัน fetchData เพื่อดึงข้อมูลจาก API
  • setData(json): เมื่อดึงข้อมูลสำเร็จ เราใช้ฟังก์ชัน setData เพื่ออัพเดทค่าของ State data ด้วยข้อมูลที่ได้จาก API
  • setLoading(false): เมื่อดึงข้อมูลเสร็จ (ไม่ว่าจะสำเร็จหรือล้มเหลว) เราใช้ฟังก์ชัน setLoading เพื่ออัพเดทค่าของ State loading เป็น false เพื่อบอกว่าการโหลดข้อมูลเสร็จสิ้นแล้ว
  • FlatList: Component นี้ใช้สำหรับแสดงรายการข้อมูลยาวๆ อย่างมีประสิทธิภาพ
  • keyExtractor: กำหนด property ที่ใช้เป็น key สำหรับแต่ละ item ใน FlatList เพื่อให้ React สามารถ update component ได้อย่างมีประสิทธิภาพ

ข้อควรระวังในการใช้ useState:

  • อย่าแก้ไข State โดยตรง: ห้ามใช้ data.push() หรือ data[0] = 'something' เพราะ React จะไม่รู้ว่า State มีการเปลี่ยนแปลง และ UI จะไม่อัพเดท ให้ใช้ฟังก์ชัน setData เสมอ
  • State เป็น Immutable: เมื่ออัพเดท State ที่เป็น Object หรือ Array ควรสร้างสำเนา (copy) ของ Object หรือ Array นั้นก่อน แล้วค่อยแก้ไขสำเนา จากนั้นค่อยส่งสำเนาไปอัพเดท State เช่น setData([...data, newItem]) (ใช้ Spread Operator)

Context API: แชร์ State ข้าม Component

Context API เป็นเครื่องมือที่ช่วยให้เราสามารถแชร์ State ระหว่าง Component ต่างๆ ได้ง่ายขึ้น โดยไม่ต้องส่ง props ผ่าน Component หลายชั้น (prop drilling) ซึ่งเป็นปัญหาที่พบบ่อยใน React Native

หลักการทำงานของ Context API:

  1. สร้าง Context: สร้าง Context Object ด้วย React.createContext()
  2. Provider: ห่อ Component ที่ต้องการแชร์ State ด้วย Context.Provider และกำหนดค่า value ที่ต้องการแชร์
  3. Consumer: ใช้ useContext Hook ใน Component ที่ต้องการเข้าถึง State

ตัวอย่างการใช้งาน Context API:

import React, { useState, useEffect, createContext, useContext } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';

// 1. สร้าง Context
const DataContext = createContext();

const App = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/todos'); // API สำหรับทดสอบ
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const json = await response.json();
        setData(json);
      } catch (error) {
        console.error('Error fetching data:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  // 2. Provider: ส่ง State ผ่าน DataContext.Provider
  return (
    <DataContext.Provider value={{ data, loading }}>
      <View style={styles.container}>
        <TodoList />
      </View>
    </DataContext.Provider>
  );
};

const TodoList = () => {
  // 3. Consumer: ใช้ useContext เพื่อเข้าถึง State
  const { data, loading } = useContext(DataContext);

  if (loading) {
    return <Text>กำลังโหลดข้อมูล...</Text>;
  }

  return (
    <FlatList
      data={data}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => (
        <View style={styles.item}>
          <Text>{item.title}</Text>
          <Text>Completed: {item.completed ? 'Yes' : 'No'}</Text>
        </View>
      )}
    />
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  item: {
    marginBottom: 10,
    padding: 10,
    borderWidth: 1,
    borderColor: '#ccc',
  },
});

export default App;

คำอธิบายโค้ด:

  • createContext(): เราสร้าง Context Object ชื่อ DataContext
  • DataContext.Provider: เราห่อ Component TodoList ด้วย DataContext.Provider และกำหนดค่า value เป็น Object ที่มี State data และ loading
  • useContext(DataContext): ใน Component TodoList เราใช้ useContext(DataContext) เพื่อเข้าถึงค่า State ที่ถูกแชร์

เมื่อไหร่ควรใช้ Context API?

  • เมื่อต้องการแชร์ State ข้าม Component หลายๆ ตัว โดยไม่ต้องส่ง props ผ่าน Component หลายชั้น
  • เมื่อ State มีความซับซ้อน และมีการเปลี่ยนแปลงบ่อย
  • เมื่อต้องการแยก Logic การจัดการ State ออกจาก Component

ข้อควรระวังในการใช้ Context API:

  • ถ้า State ที่แชร์มีการเปลี่ยนแปลงบ่อยๆ อาจทำให้ Component ที่ใช้ Context ถูก re-render บ่อยเกินไป
  • สำหรับ State ที่ไม่ซับซ้อน และใช้แค่ใน Component เดียว useState อาจเป็นทางเลือกที่ดีกว่า

การอัพเดท State: ข้อควรจำ

ไม่ว่าเราจะใช้ useState หรือ Context API สิ่งที่สำคัญที่สุดคือการอัพเดท State อย่างถูกต้อง เพื่อให้ React Native สามารถ Render UI ได้อย่างถูกต้องและมีประสิทธิภาพ

หลักการสำคัญในการอัพเดท State:

  • Immutability: State ใน React Native เป็น Immutable นั่นหมายความว่าเราไม่ควรแก้ไข State โดยตรง แต่ควรสร้างสำเนา (copy) ของ State แล้วค่อยแก้ไขสำเนา จากนั้นค่อยส่งสำเนาไปอัพเดท State
  • Functional Updates: เมื่ออัพเดท State ที่ขึ้นอยู่กับค่า State ก่อนหน้า เราควรใช้ Functional Updates เพื่อให้แน่ใจว่าเราใช้ค่า State ที่ถูกต้องที่สุด เช่น setData(prevData => [...prevData, newItem])

ในบทนี้เราได้เรียนรู้เกี่ยวกับการจัดการ State ของข้อมูลที่ได้จาก API ด้วย useState Hook และ Context API ซึ่งเป็นเครื่องมือที่สำคัญในการพัฒนา React Native application อย่าลืมฝึกฝนและนำไปประยุกต์ใช้กับโปรเจกต์ของคุณนะครับ ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับการใช้ Axios Library ซึ่งเป็นอีกทางเลือกหนึ่งในการเชื่อมต่อ API ที่ได้รับความนิยมเช่นกัน แล้วเจอกันครับ!

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기