Context
SSD's React component writing must use the functional component pattern with TypeScript (TSX) and must follow the specified naming conventions so that the code is easy to read, easy to maintain, and can be automation tested.
Main Rules
- Must create 1 component per 1 file (except Stateless/Pure components)
- Must always use TSX with React. Do not use
React.createElement - Must declare the Props type and export it every time there are Props
- The Props type name must follow the format
[ComponentName]Props - Must use arrow functions for event handlers
- Must use the shorthand fragment
<>...</>instead of<React.Fragment> - Must use
ref callbackDo not use string ref
Component Creation Steps
Step 1: Use the tsrafce snippet
Type tsrafce in VS Code to create a template component from the ES7+ React snippets plugin
Step 2: Declare the Props type
// ชื่อ Props type ต้องลงท้ายด้วย Props และขึ้นต้นด้วยชื่อ Component
export type OrderTableProps = {
orderId: number;
orderDate: string;
isActive?: boolean; // optional ใช้ ? แทน | undefined
}
Step 3: Write the Component
// Naming Convention:
// - ชื่อ Component = PascalCase
// - ชื่อ Props type = [ComponentName]Props
// - ลงท้ายด้วย Props เสมอ
export type OrderTableProps = {
title: string;
onSubmit?: () => void;
}
const OrderTable = ({ title, onSubmit }: OrderTableProps) => {
return (
<div>
<h1>{title}</h1>
</div>
);
};
export default OrderTable;
Props Standards
Name Props with camelCase
// ไม่ดี
<Foo UserName="hello" phone_number={12345678} />
// ดี
<Foo userName="hello" phoneNumber={12345678} />
Boolean Props do not need to specify the value true
// ไม่ดี
<Foo hidden={true} />
// ดี
<Foo hidden />
Do not use index as the key in map
// ไม่ดี
{todos.map((todo, index) => <Todo {...todo} key={index} />)}
// ดี
{todos.map((todo) => <Todo {...todo} key={todo.id} />)}
Do not use DOM props as prop names
// ไม่ดี
<MyComponent style="fancy" />
<MyComponent className="fancy" />
// ดี
<MyComponent variant="fancy" />
Method and Event Handler Standards
Always use arrow functions, especially when additional data must be passed:
const ItemList = ({ items }: ItemListProps) => {
const doSomethingWith = (
event: React.MouseEvent,
name: string,
index: number
) => {
// do something
};
return (
<ul>
{items.map((item, index) => (
<Item
key={item.key}
onClick={(event) => {
doSomethingWith(event, item.name, index);
}}
/>
))}
</ul>
);
};
Refs Standards
// ไม่ดี
<Foo ref="myRef" />
// ดี
<Foo ref={myRef} />
Fragment Standards
// ไม่ดี
return (
<React.Fragment>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</React.Fragment>
);
// ดี
return (
<>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</>
);
Import Standards
// ชื่อ component ต้องใช้ PascalCase เมื่อ import
// ไม่ดี
import reservationCard from "./ReservationCard";
// ดี
import ReservationCard from "./ReservationCard";
// component หลักของ folder ให้ import จากชื่อ folder
// ไม่ดี
import Footer from "./Footer/Footer";
// ไม่ดี
import Footer from "./Footer/index";
// ดี
import Footer from "./Footer";
Principles for Naming Components, Pages, Modules
Module
- Start with an uppercase PascalCase letter
- No more than 3 words
Component
- Start with an uppercase PascalCase letter
- No more than 3 words
- Custom hooks are separated into files and named with
.hook.tsx - Naming suffixes:
Container,View,Card,Form,Table,List,Item - Formik components: end with the name of the MUI component, e.g.
ProvinceSelect,GenderRadioGroup
Page
- Start with an uppercase letter, end with
Page - No more than 3 words
- The homepage of the module must be named
IndexPage - Every module must have
IndexPage
Authorization check in Component
import { PermissionList } from "/src/Const";
import { checkPermissions, useAuth } from "/src/app/modules/_auth";
const { permissions } = useAuth();
// เช็ค permission (default condition เป็น "OR")
const hasPermission: boolean = checkPermissions(
permissions,
[
PermissionList.employee_read,
PermissionList.employee_write,
],
"AND" // หรือ "OR"
);
Fetch User data
import { useAuth } from "/src/app/modules/_auth";
const { user, userProfile, isAuthenticated, permissions, roles } = useAuth();
// ใช้ข้อมูลจาก userProfile
// userProfile.userId, userProfile.userName, userProfile.email
// userProfile.employeeId, userProfile.employeeCode, userProfile.fullName
// userProfile.branchId, userProfile.departmentId, userProfile.teamId, userProfile.positionId