React Native ฉบับเริ่มต้น: สร้างแอปมือถือข้ามแพลตฟอร์ม - ตอนที่ 15: Custom Component: สร้าง Component ของตัวเอง
สวัสดีครับ กลับมาพบกันอีกครั้งในบทเรียน React Native ครับ! ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้งาน ActivityIndicator เพื่อแสดงสถานะ Loading ให้ผู้ใช้ทราบว่าแอปพลิเคชันของเรากำลังทำงานอยู่เบื้องหลัง ซึ่งเป็นส่วนสำคัญในการสร้างประสบการณ์ใช้งานที่ดี ในบทนี้ เราจะก้าวไปอีกขั้นด้วยการสร้าง Custom Component หรือ Component ที่เราสร้างขึ้นเอง เพื่อนำไปใช้งานซ้ำ ๆ ในหลาย ๆ ที่ ลดความซ้ำซ้อนของโค้ด และทำให้โค้ดของเราอ่านง่ายและเป็นระเบียบมากยิ่งขึ้น
ลองนึกภาพว่าเราต้องสร้างปุ่มที่มีสไตล์เดียวกัน แต่ใช้ในหลายหน้าจอของแอปพลิเคชัน ถ้าเราคัดลอกโค้ดของปุ่มไปวางในทุกหน้าจอ เมื่อเราต้องการแก้ไขสไตล์ของปุ่ม เราจะต้องแก้ไขในทุก ๆ หน้าจอ ซึ่งเป็นเรื่องที่น่าเบื่อและเสียเวลามาก แต่ถ้าเราสร้าง Custom Component สำหรับปุ่มนี้ เราก็แค่แก้ไขที่ Component เดียว แล้วทุกปุ่มที่ใช้ Component นี้ก็จะได้รับการอัปเดตทั้งหมด
ทำไมต้องสร้าง Custom Component?
การสร้าง Custom Component มีประโยชน์มากมาย ดังนี้:
- Reusability (การนำกลับมาใช้ใหม่ได้): สร้าง Component ครั้งเดียว แล้วนำไปใช้ได้ในหลาย ๆ ที่
- Modularity (ความเป็นโมดูล): แยกโค้ดออกเป็นส่วน ๆ ทำให้โค้ดอ่านง่ายและจัดการได้ง่ายขึ้น
- Maintainability (การบำรุงรักษา): แก้ไข Component เดียว ก็จะส่งผลต่อทุกที่ที่ใช้ Component นั้น
- Testability (การทดสอบ): สามารถทดสอบ Component ได้อย่างอิสระ
- Abstraction (ความเป็นนามธรรม): ซ่อนรายละเอียดการทำงานภายใน Component ทำให้โค้ดที่เรียกใช้ Component นั้นง่ายขึ้น
การสร้าง Custom Component
การสร้าง Custom Component ใน React Native นั้นง่ายมากครับ เราสามารถสร้าง Component ได้ทั้งแบบ Function Component และ Class Component ในบทนี้ เราจะเน้นไปที่ Function Component เพราะเป็นรูปแบบที่นิยมใช้กันในปัจจุบัน
โดยพื้นฐานแล้ว Custom Component ก็คือ Function ที่ return JSX ครับ เราจะสร้างไฟล์ใหม่ (เช่น MyButton.js) แล้วเขียนโค้ด Component ของเราลงไป
// MyButton.js
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
const MyButton = (props) => {
return (
<TouchableOpacity style={styles.button} onPress={props.onPress}>
<Text style={styles.buttonText}>{props.title}</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
button: {
backgroundColor: '#4CAF50',
padding: 10,
borderRadius: 5,
alignItems: 'center',
},
buttonText: {
color: 'white',
fontSize: 16,
},
});
export default MyButton;
ในตัวอย่างนี้ เราสร้าง Component ชื่อ MyButton ซึ่งรับ props (properties) เป็น argument หนึ่งในนั้นคือ onPress ซึ่งเป็น function ที่จะถูกเรียกเมื่อผู้ใช้กดปุ่ม และ title ซึ่งเป็นข้อความที่จะแสดงบนปุ่ม นอกจากนี้ เรายังใช้ StyleSheet เพื่อกำหนดสไตล์ให้กับปุ่มของเรา
การรับ Props ใน Custom Component
อย่างที่กล่าวไปข้างต้น Custom Component สามารถรับ props ได้ ซึ่งเป็นวิธีที่เราส่งข้อมูลจาก Component แม่ไปยัง Custom Component ของเรา props เป็น object ที่มี key-value pairs โดย key คือชื่อของ prop และ value คือค่าของ prop นั้นเอง
ในตัวอย่าง MyButton เราใช้ props.onPress และ props.title เพื่อเข้าถึงค่าของ props ที่ส่งเข้ามา เราสามารถส่ง props ได้โดยการกำหนด attribute ให้กับ Component ของเราเมื่อเราเรียกใช้งาน
การใช้ Custom Component ในหลายหน้า
เมื่อเราสร้าง Custom Component แล้ว เราสามารถนำไปใช้ใน Component อื่น ๆ ได้โดยการ import Component นั้นเข้ามา แล้วเรียกใช้งานเหมือน Component ทั่วไป
// HomeScreen.js
import React from 'react';
import { View, Text } from 'react-native';
import MyButton from './MyButton';
const HomeScreen = () => {
const handlePress = () => {
alert('Button Pressed!');
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Welcome to Home Screen!</Text>
<MyButton title="Press Me!" onPress={handlePress} />
</View>
);
};
export default HomeScreen;
ในตัวอย่างนี้ เรา import MyButton เข้ามาใน HomeScreen แล้วเรียกใช้งานโดยส่ง title และ onPress เป็น props
Trade-offs และแนวปฏิบัติที่ดี:
- Component ขนาดเล็ก: พยายามสร้าง Component ที่มีขนาดเล็กและรับผิดชอบหน้าที่เดียว (Single Responsibility Principle) จะทำให้ Component นั้นนำกลับมาใช้ใหม่ได้ง่ายขึ้น และทดสอบได้ง่ายขึ้น
- Props ที่ชัดเจน: กำหนด types ของ props ให้ชัดเจน เพื่อป้องกันข้อผิดพลาดจากการส่ง props ที่ไม่ถูกต้อง คุณสามารถใช้ TypeScript หรือ PropTypes เพื่อช่วยในการกำหนด types
- Avoid Over-Engineering: อย่าพยายามสร้าง Component ที่ซับซ้อนเกินความจำเป็น เริ่มต้นด้วย Component ที่เรียบง่าย แล้วค่อย ๆ เพิ่มความสามารถตามความต้องการ
- Composition over Inheritance: ใช้ Composition (การประกอบ Component) แทน Inheritance (การสืบทอด Component) เพื่อสร้าง Component ที่ยืดหยุ่นและนำกลับมาใช้ใหม่ได้ง่ายขึ้น
ตัวอย่างเพิ่มเติม: Custom Input Component
ลองสร้าง Custom Component สำหรับ Input Field ที่มีการจัดการ State ภายในตัวเอง และสามารถปรับแต่ง Style ได้ง่าย
// MyTextInput.js
import React, { useState } from 'react';
import { TextInput, View, StyleSheet } from 'react-native';
const MyTextInput = (props) => {
const [text, setText] = useState('');
const handleChangeText = (newText) => {
setText(newText);
if (props.onChangeText) {
props.onChangeText(newText); // Pass the text to the parent component if needed
}
};
return (
<View style={styles.container}>
<TextInput
style={[styles.input, props.style]} // Allow overriding styles from parent
value={text}
onChangeText={handleChangeText}
placeholder={props.placeholder}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginBottom: 10,
},
input: {
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
borderRadius: 5,
fontSize: 16,
},
});
export default MyTextInput;
ในตัวอย่างนี้ MyTextInput มี State ภายในตัวเองเพื่อเก็บค่าของ Input Field และมี onChangeText prop เพื่อให้ Component แม่สามารถรับรู้ถึงการเปลี่ยนแปลงของค่า Input ได้ นอกจากนี้ เรายังอนุญาตให้ Component แม่สามารถ override styles ของ Input Field ได้โดยการส่ง style prop
การใช้งาน MyTextInput:
// AnotherComponent.js
import React, { useState } from 'react';
import { View, Text } from 'react-native';
import MyTextInput from './MyTextInput';
const AnotherComponent = () => {
const [inputValue, setInputValue] = useState('');
const handleInputChange = (text) => {
setInputValue(text);
};
return (
<View>
<Text>Input Value: {inputValue}</Text>
<MyTextInput
placeholder="Enter text here"
onChangeText={handleInputChange}
style={{ borderColor: 'blue' }} // Override the border color
/>
</View>
);
};
export default AnotherComponent;
สรุป:
การสร้าง Custom Component เป็นทักษะที่สำคัญมากในการพัฒนา React Native ครับ ช่วยให้เราเขียนโค้ดได้ง่ายขึ้น เป็นระเบียบมากขึ้น และนำกลับมาใช้ใหม่ได้ง่ายขึ้น อย่ากลัวที่จะสร้าง Component ของตัวเอง ลองเริ่มจาก Component ที่เรียบง่าย แล้วค่อย ๆ พัฒนาไปเรื่อย ๆ ครับ
ในบทถัดไป เราจะเรียนรู้เกี่ยวกับการจัดการ Form ด้วย Formik และ Yup ซึ่งเป็น Library ที่ช่วยให้การจัดการ Form ใน React Native ง่ายขึ้นมาก อย่าลืมติดตามนะครับ!