Dark mode
Best Practices in React Development
Component Design
- Follow Single Responsibility Principle
tsx
// Bad: Component ที่ทำหลายหน้าที่
function UserProfile({ user }) {
return (
<div>
<img src={user.avatar} />
<button onClick={() => fetchDetails(user.id)}>Load Details</button>
<UserDetails data={user.details} />
</div>
);
}
// Good: แยกเป็นคอมโพเนนต์ย่อย
function UserAvatar({ src }) {
return <img src={src} />;
}
function ProfileActions({ userId }) {
const handleClick = () => fetchDetails(userId);
return <button onClick={handleClick}>Load Details</button>;
}
- Use composition over inheritance
tsx
// ตัวอย่างการใช้งาน Composition ที่ดี
function Dashboard({ children }) {
return (
<div className="dashboard">
<Header />
<div className="content">
{children}
</div>
<Footer />
</div>
);
}
// การใช้งาน
<Dashboard>
<UserProfile />
<NotificationList />
</Dashboard>;
- Prefer small, reusable components
การออกแบบคอมโพเนนต์
- ปฏิบัติตามหลัก Single Responsibility Principle
- ใช้ composition แทน inheritance
- เลือกใช้คอมโพเนนต์ขนาดเล็กที่นำกลับมาใช้ใหม่ได้
Performance
- Use React.memo for optimization
tsx
// ควรใช้ memo เมื่อ:
// 1. คอมโพเนนต์เรนเดอร์บ่อยแต่ props ไม่เปลี่ยน
// 2. คอมโพเนนต์มีขนาดใหญ่
const HeavyComponent = React.memo(({ data }) => {
// คำนวณอะไรที่ซับซ้อน
return <ExpensiveRender data={data} />;
});
- Avoid unnecessary re-renders
- Use useCallback/useMemo appropriately
tsx
function ProductList({ products }) {
// ใช้ useMemo เมื่อคำนวณค่าแพง
const featuredProducts = useMemo(
() => products.filter(p => p.isFeatured),
[products],
);
// ใช้ useCallback สำหรับ event handler
const handleAddToCart = useCallback((productId) => {
addToCart(productId);
}, []);
return (
<ul>
{featuredProducts.map(product => (
<ProductItem
key={product.id}
product={product}
onAdd={handleAddToCart}
/>
))}
</ul>
);
}
ประสิทธิภาพ
- ใช้ React.memo เพื่อเพิ่มประสิทธิภาพ
- หลีกเลี่ยงการ re-render ที่ไม่จำเป็น
- ใช้ useCallback/useMemo อย่างเหมาะสม
Code Organization
- Group by feature, not by type
src/
features/
user/
UserProfile.tsx
useUser.ts
userApi.ts
components/
UserAvatar.tsx
UserActions.tsx
products/
ProductList.tsx
useProducts.ts
components/
ProductCard.tsx
- Use index files for clean imports
- Separate concerns with custom hooks
การจัดระเบียบโค้ด
- จัดกลุ่มตามฟีเจอร์ ไม่ใช่ตามประเภท
- ใช้ไฟล์ index เพื่อให้การ import สะอาดขึ้น
- แยกความรับผิดชอบด้วย custom hooks
Testing
- Write unit tests with Jest + React Testing Library
- Test behavior, not implementation
tsx
// ทดสอบว่าผู้ใช้สามารถล็อกอินได้
test("should allow user to login", async () => {
render(<LoginPage />);
// 1. หาช่อง input
const emailInput = screen.getByLabelText("Email");
const passwordInput = screen.getByLabelText("Password");
// 2. จำลองการพิมพ์
userEvent.type(emailInput, "[email protected]");
userEvent.type(passwordInput, "password123");
// 3. จำลองการคลิก
fireEvent.click(screen.getByText("Login"));
// 4. ตรวจสอบผลลัพธ์
await waitFor(() => {
expect(screen.getByText("Welcome back!")).toBeInTheDocument();
});
});
- Aim for good coverage of critical paths
การทดสอบ
- เขียน unit test ด้วย Jest + React Testing Library
- ทดสอบที่ behavior ไม่ใช่ implementation
- ตั้งเป้าหมายให้ครอบคลุม critical paths